<commit_before>package main // See https://github.com/kataras/iris/issues/1601

import (
	"time"

	"github.com/kataras/iris/v12"
	"github.com/kataras/iris/v12/middleware/accesslog"
	"github.com/kataras/iris/v12/middleware/basicauth"
	"github.com/kataras/iris/v12/middleware/requestid"
	"github.com/kataras/iris/v12/sessions"

	rotatelogs "github.com/lestrrat-go/file-rotatelogs"
)

func makeAccessLog() *accesslog.AccessLog {
	// Optionally, let's Go with log rotation.
	pathToAccessLog := "./access_log.%Y%m%d%H%M"
	w, err := rotatelogs.New(
		pathToAccessLog,
		rotatelogs.WithMaxAge(24*time.Hour),
		rotatelogs.WithRotationTime(time.Hour))
	if err != nil {
		panic(err)
	}

	// Initialize a new access log middleware.
	// Accepts an `io.Writer`.
	ac := accesslog.New(w)
	ac.TimeFormat = "2006-01-02 15:04:05"

	// Example of adding more than one field to the logger.
	// Here we logging all the session values this request has.
	//
	// You can also add fields per request handler,
	// look below to the `fieldsHandler` function.
	// Note that this method can override a key stored by a handler's fields.
	ac.AddFields(func(ctx iris.Context, fields *accesslog.Fields) {
		if sess := sessions.Get(ctx); sess != nil {
			fields.Set("session_id", sess.ID())

			sess.Visit(func(k string, v interface{}) {
				fields.Set(k, v)
			})
		}
	})
	// Add a custom field of "auth" when basic auth is available.
	ac.AddFields(func(ctx iris.Context, fields *accesslog.Fields) {
		if username, password, ok := ctx.Request().BasicAuth(); ok {
			fields.Set("auth", username+":"+password)
		}
	})

	return ac

	/*
		Use a file directly:
		ac := accesslog.File("./access.log")

		Log after the response was sent (defaults to false):
		ac.Async = true

		Force-protect writer with locks.
		On this example this is not required:
		ac.LockWriter = true"

		// To disable request and response calculations
		// (enabled by default but slows down the whole operation if Async is false):
		ac.RequestBody = false
		ac.ResponseBody = false
		ac.BytesReceived = false
		ac.BytesSent = false

		Add second output:
		ac.AddOutput(app.Logger().Printer)
		OR:
		accesslog.New(io.MultiWriter(w, os.Stdout))

		Change format (after output was set):
		ac.SetFormatter(&accesslog.JSON{Indent: "  "})

		Modify the output format and customize the order
		with the Template formatter:
		ac.SetFormatter(&accesslog.Template{
		    Text: "{{.Now.Format .TimeFormat}}|{{.Latency}}|{{.Method}}|{{.Path}}|{{.RequestValuesLine}}|{{.Code}}|{{.BytesReceivedLine}}|{{.BytesSentLine}}|{{.Request}}|{{.Response}}|\n",
		    // Default ^
		})
	*/
}

func main() {
	ac := makeAccessLog()

	defer ac.Close()
	iris.RegisterOnInterrupt(func() {
		ac.Close()
	})

	app := iris.New()
	// Register the middleware (UseRouter to catch http errors too).
	app.UseRouter(ac.Handler)
	//

	// Register other middlewares...
	app.UseRouter(requestid.New())

	// Register some routes...
	app.HandleDir("/", iris.Dir("./public"))

	app.Get("/user/{username}", userHandler)
	app.Post("/read_body", readBodyHandler)
	app.Get("/html_response", htmlResponse)

	basicAuth := basicauth.Default(map[string]string{
		"admin": "admin",
	})
	app.Get("/admin", basicAuth, adminHandler)

	sess := sessions.New(sessions.Config{Cookie: "my_session_id", AllowReclaim: true})
	app.Get("/session", sess.Handler(), sessionHandler)

	app.Get("/fields", fieldsHandler)
	//

	app.Listen(":8080")
}

func readBodyHandler(ctx iris.Context) {
	var request interface{}
	if err := ctx.ReadBody(&request); err != nil {
		ctx.StopWithPlainError(iris.StatusBadRequest, err)
		return
	}

	ctx.JSON(iris.Map{"message": "OK", "data": request})
}

func userHandler(ctx iris.Context) {
	ctx.Writef("Hello, %s!", ctx.Params().Get("username"))
}

func htmlResponse(ctx iris.Context) {
	ctx.HTML("
HTML Response
")
}

func adminHandler(ctx iris.Context) {
	username, password, _ := ctx.Request().BasicAuth()
	// of course you don't want that in production:
	ctx.HTML("
Username: %s

Password: %s
", username, password)
}

func sessionHandler(ctx iris.Context) {
	sess := sessions.Get(ctx)
	sess.Set("session_test_key", "session_test_value")

	ctx.WriteString("OK")
}

func fieldsHandler(ctx iris.Context) {
	// simulate a heavy job...
	start := time.Now()
	time.Sleep(2 * time.Second)
	end := time.Since(start)
	// Get the current fields instance and use
	// them to it custom log values.
	logFields := accesslog.GetFields(ctx)
	logFields.Set("job_latency", end.Round(time.Second))

	ctx.WriteString("OK")
}
<commit_msg>minor<commit_after>package main // See https://github.com/kataras/iris/issues/1601

import (
	"time"

	"github.com/kataras/iris/v12"
	"github.com/kataras/iris/v12/middleware/accesslog"
	"github.com/kataras/iris/v12/middleware/basicauth"
	"github.com/kataras/iris/v12/middleware/requestid"
	"github.com/kataras/iris/v12/sessions"

	rotatelogs "github.com/lestrrat-go/file-rotatelogs"
)

func makeAccessLog() *accesslog.AccessLog {
	// Optionally, let's Go with log rotation.
	pathToAccessLog := "./access_log.%Y%m%d%H%M"
	w, err := rotatelogs.New(
		pathToAccessLog,
		rotatelogs.WithMaxAge(24*time.Hour),
		rotatelogs.WithRotationTime(time.Hour))
	if err != nil {
		panic(err)
	}

	// Initialize a new access log middleware.
	// Accepts an `io.Writer`.
	ac := accesslog.New(w)
	ac.TimeFormat = "2006-01-02 15:04:05"

	// Example of adding more than one field to the logger.
	// Here we logging all the session values this request has.
	//
	// You can also add fields per request handler,
	// look below to the `fieldsHandler` function.
	// Note that this method can override a key stored by a handler's fields.
	ac.AddFields(func(ctx iris.Context, fields *accesslog.Fields) {
		if sess := sessions.Get(ctx); sess != nil {
			fields.Set("session_id", sess.ID())

			sess.Visit(func(k string, v interface{}) {
				fields.Set(k, v)
			})
		}
	})
	// Add a custom field of "auth" when basic auth is available.
	ac.AddFields(func(ctx iris.Context, fields *accesslog.Fields) {
		if username, password, ok := ctx.Request().BasicAuth(); ok {
			fields.Set("auth", username+":"+password)
		}
	})

	return ac

	/*
		Use a file directly:
		ac := accesslog.File("./access.log")

		Log after the response was sent (defaults to false):
		ac.Async = true

		Force-protect writer with locks.
		On this example this is not required:
		ac.LockWriter = true"

		// To disable request and response calculations
		// (enabled by default but slows down the whole operation if Async is false):
		ac.RequestBody = false
		ac.ResponseBody = false
		ac.BytesReceived = false
		ac.BytesSent = false

		Add second output:
		ac.AddOutput(app.Logger().Printer)
		OR:
		accesslog.New(io.MultiWriter(w, os.Stdout))

		Change format (after output was set):
		ac.SetFormatter(&accesslog.JSON{Indent: "  "})

		Modify the output format and customize the order
		with the Template formatter:
		ac.SetFormatter(&accesslog.Template{
		    Text: "{{.Now.Format .TimeFormat}}|{{.Latency}}|{{.Method}}|{{.Path}}|{{.RequestValuesLine}}|{{.Code}}|{{.BytesReceivedLine}}|{{.BytesSentLine}}|{{.Request}}|{{.Response}}|\n",
		    // Default ^
		})
	*/
}

func main() {
	ac := makeAccessLog()

	defer ac.Close()
	iris.RegisterOnInterrupt(func() {
		ac.Close()
	})

	app := iris.New()
	// Register the middleware (UseRouter to catch http errors too).
	app.UseRouter(ac.Handler)
	//

	// Register other middlewares...
	app.UseRouter(requestid.New())

	// Register some routes...
	app.HandleDir("/", iris.Dir("./public"))

	app.Get("/user/{username}", userHandler)
	app.Post("/read_body", readBodyHandler)
	app.Get("/html_response", htmlResponse)

	basicAuth := basicauth.Default(map[string]string{
		"admin": "admin",
	})
	app.Get("/admin", basicAuth, adminHandler)

	sess := sessions.New(sessions.Config{Cookie: "my_session_id", AllowReclaim: true})
	app.Get("/session", sess.Handler(), sessionHandler)

	app.Get("/fields", fieldsHandler)
	//

	app.Listen(":8080")
}

func readBodyHandler(ctx iris.Context) {
	var request interface{}
	if err := ctx.ReadBody(&request); err != nil {
		ctx.StopWithPlainError(iris.StatusBadRequest, err)
		return
	}

	ctx.JSON(iris.Map{"message": "OK", "data": request})
}

func userHandler(ctx iris.Context) {
	ctx.Writef("Hello, %s!", ctx.Params().Get("username"))
}

func htmlResponse(ctx iris.Context) {
	ctx.HTML("
HTML Response
")
}

func adminHandler(ctx iris.Context) {
	username, password, _ := ctx.Request().BasicAuth()
	// of course you don't want that in production:
	ctx.HTML("
Username: %s

Password: %s
", username, password)
}

func sessionHandler(ctx iris.Context) {
	sess := sessions.Get(ctx)
	sess.Set("session_test_key", "session_test_value")

	ctx.WriteString("OK")
}

func fieldsHandler(ctx iris.Context) {
	start := time.Now()
	// simulate a heavy job...
	time.Sleep(2 * time.Second)
	end := time.Since(start)
	// Get the current fields instance
	// and use it to set custom log values.
	logFields := accesslog.GetFields(ctx)
	logFields.Set("job_latency", end.Round(time.Second))

	ctx.WriteString("OK")
}
<|endoftext|>


<commit_before>package connection_test

import (
	"net"
	"testing"

	"github.com/cenkalti/mse"

	"github.com/cenkalti/rain/internal/connection"
	"github.com/cenkalti/rain/internal/protocol"
)

var addr = &net.TCPAddr{
	IP:   net.IPv4(127, 0, 0, 1),
	Port: 5000,
}

var (
	ext1     = [8]byte{0x0A}
	ext2     = [8]byte{0x0B}
	id1      = protocol.PeerID{0x0C}
	id2      = protocol.PeerID{0x0D}
	infoHash = protocol.InfoHash{0x0E}
	sKeyHash = mse.HashSKey(infoHash[:])
)

func TestUnencrypted(t *testing.T) {
	l, err := net.ListenTCP("tcp", addr)
	if err != nil {
		t.Fatal(err)
	}
	defer l.Close()
	done := make(chan struct{})
	go func() {
		conn, cipher, ext, id, err := connection.Dial(addr, false, false, ext1, infoHash, id1)
		if err != nil {
			t.Fatal(err)
		}
		if conn == nil {
			t.Errorf("conn: %s", conn)
		}
		if cipher != 0 {
			t.Errorf("cipher: %d", cipher)
		}
		if ext != ext2 {
			t.Errorf("ext: %s", ext)
		}
		if id != id2 {
			t.Errorf("id: %s", id)
		}
		close(done)
	}()
	conn, err := l.Accept()
	if err != nil {
		t.Fatal(err)
	}
	_, cipher, ext, ih, id, err := connection.Accept(conn, nil, false, func(ih protocol.InfoHash) bool { return ih == infoHash }, ext2, id2)
	<-done
	if err != nil {
		t.Fatal(err)
	}
	if cipher != 0 {
		t.Errorf("cipher: %d", cipher)
	}
	if ext != ext1 {
		t.Errorf("ext: %s", ext)
	}
	if ih != infoHash {
		t.Errorf("ih: %s", ih)
	}
	if id != id1 {
		t.Errorf("id: %s", id)
	}
}

func TestEncrypted(t *testing.T) {
	l, err := net.ListenTCP("tcp", addr)
	if err != nil {
		t.Fatal(err)
	}
	defer l.Close()
	done := make(chan struct{})
	go func() {
		conn, cipher, ext, id, err := connection.Dial(addr, true, false, ext1, infoHash, id1)
		if err != nil {
			t.Fatal(err)
		}
		if conn == nil {
			t.Errorf("conn: %s", conn)
		}
		if cipher != mse.RC4 {
			t.Errorf("cipher: %d", cipher)
		}
		if ext != ext2 {
			t.Errorf("ext: %s", ext)
		}
		if id != id2 {
			t.Errorf("id: %s", id)
		}
		close(done)
	}()
	conn, err := l.Accept()
	if err != nil {
		t.Fatal(err)
	}
	_, cipher, ext, ih, id, err := connection.Accept(
		conn,
		func(h [20]byte) (sKey []byte) {
			if h == sKeyHash {
				return infoHash[:]
			}
			return nil
		},
		false,
		func(ih protocol.InfoHash) bool { return ih == infoHash },
		ext2, id2)
	<-done
	if err != nil {
		t.Fatal(err)
	}
	if cipher != mse.RC4 {
		t.Errorf("cipher: %d", cipher)
	}
	if ext != ext1 {
		t.Errorf("ext: %s", ext)
	}
	if ih != infoHash {
		t.Errorf("ih: %s", ih)
	}
	if id != id1 {
		t.Errorf("id: %s", id)
	}
}
<commit_msg>add read/write message to connection test<commit_after>package connection_test

import (
	"net"
	"testing"

	"github.com/cenkalti/mse"

	"github.com/cenkalti/rain/internal/connection"
	"github.com/cenkalti/rain/internal/protocol"
)

var addr = &net.TCPAddr{
	IP:   net.IPv4(127, 0, 0, 1),
	Port: 5000,
}

var (
	ext1     = [8]byte{0x0A}
	ext2     = [8]byte{0x0B}
	id1      = protocol.PeerID{0x0C}
	id2      = protocol.PeerID{0x0D}
	infoHash = protocol.InfoHash{0x0E}
	sKeyHash = mse.HashSKey(infoHash[:])
)

func TestUnencrypted(t *testing.T) {
	l, err := net.ListenTCP("tcp", addr)
	if err != nil {
		t.Fatal(err)
	}
	defer l.Close()
	done := make(chan struct{})
	go func() {
		conn, cipher, ext, id, err := connection.Dial(addr, false, false, ext1, infoHash, id1)
		if err != nil {
			t.Fatal(err)
		}
		if conn == nil {
			t.Errorf("conn: %s", conn)
		}
		if cipher != 0 {
			t.Errorf("cipher: %d", cipher)
		}
		if ext != ext2 {
			t.Errorf("ext: %s", ext)
		}
		if id != id2 {
			t.Errorf("id: %s", id)
		}
		close(done)
	}()
	conn, err := l.Accept()
	if err != nil {
		t.Fatal(err)
	}
	_, cipher, ext, ih, id, err := connection.Accept(conn, nil, false, func(ih protocol.InfoHash) bool { return ih == infoHash }, ext2, id2)
	<-done
	if err != nil {
		t.Fatal(err)
	}
	if cipher != 0 {
		t.Errorf("cipher: %d", cipher)
	}
	if ext != ext1 {
		t.Errorf("ext: %s", ext)
	}
	if ih != infoHash {
		t.Errorf("ih: %s", ih)
	}
	if id != id1 {
		t.Errorf("id: %s", id)
	}
}

func TestEncrypted(t *testing.T) {
	l, err := net.ListenTCP("tcp", addr)
	if err != nil {
		t.Fatal(err)
	}
	defer l.Close()
	done := make(chan struct{})
	go func() {
		conn, cipher, ext, id, err := connection.Dial(addr, true, false, ext1, infoHash, id1)
		if err != nil {
			t.Fatal(err)
		}
		if conn == nil {
			t.Errorf("conn: %s", conn)
		}
		if cipher != mse.RC4 {
			t.Errorf("cipher: %d", cipher)
		}
		if ext != ext2 {
			t.Errorf("ext: %s", ext)
		}
		if id != id2 {
			t.Errorf("id: %s", id)
		}
		_, err = conn.Write([]byte("hello out"))
		if err != nil {
			t.Fail()
		}
		b := make([]byte, 10)
		n, err := conn.Read(b)
		if err != nil {
			t.Error(err)
		}
		if n != 8 {
			t.Fail()
		}
		if string(b[:8]) != "hello in" {
			t.Fail()
		}
		close(done)
	}()
	conn, err := l.Accept()
	if err != nil {
		t.Fatal(err)
	}
	encConn, cipher, ext, ih, id, err := connection.Accept(
		conn,
		func(h [20]byte) (sKey []byte) {
			if h == sKeyHash {
				return infoHash[:]
			}
			return nil
		},
		false,
		func(ih protocol.InfoHash) bool { return ih == infoHash },
		ext2, id2)
	if err != nil {
		t.Fatal(err)
	}
	if cipher != mse.RC4 {
		t.Errorf("cipher: %d", cipher)
	}
	if ext != ext1 {
		t.Errorf("ext: %s", ext)
	}
	if ih != infoHash {
		t.Errorf("ih: %s", ih)
	}
	if id != id1 {
		t.Errorf("id: %s", id)
	}
	b := make([]byte, 10)
	n, err := encConn.Read(b)
	if err != nil {
		t.Error(err)
	}
	if n != 9 {
		t.Fail()
	}
	if string(b[:9]) != "hello out" {
		t.Fail()
	}
	_, err = encConn.Write([]byte("hello in"))
	if err != nil {
		t.Fail()
	}
	<-done
}
<|endoftext|>


<commit_before>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package mmlogic

import (
	"github.com/sirupsen/logrus"
	"google.golang.org/grpc"
	"open-match.dev/open-match/internal/config"
	"open-match.dev/open-match/internal/future/pb"
	"open-match.dev/open-match/internal/future/serving"
)

var (
	mmlogicLogger = logrus.WithFields(logrus.Fields{
		"app":       "openmatch",
		"component": "backend",
	})
)

// RunApplication creates a server.
func RunApplication() {
	cfg, err := config.Read()
	if err != nil {
		mmlogicLogger.WithFields(logrus.Fields{
			"error": err.Error(),
		}).Fatalf("cannot read configuration.")
	}
	p, err := serving.NewParamsFromConfig(cfg, "api.backend")
	if err != nil {
		mmlogicLogger.WithFields(logrus.Fields{
			"error": err.Error(),
		}).Fatalf("cannot construct server.")
	}

	BindService(p)
	serving.MustServeForever(p)
}

// BindService creates the mmlogic service to the server Params.
func BindService(p *serving.Params) {
	service := &mmlogicService{}
	p.AddHandleFunc(func(s *grpc.Server) {
		pb.RegisterMmLogicServer(s, service)
	}, pb.RegisterMmLogicHandlerFromEndpoint)
}
<commit_msg>Fix mmlogic readiness probe. (#357)<commit_after>// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package mmlogic

import (
	"github.com/sirupsen/logrus"
	"google.golang.org/grpc"
	"open-match.dev/open-match/internal/config"
	"open-match.dev/open-match/internal/future/pb"
	"open-match.dev/open-match/internal/future/serving"
)

var (
	mmlogicLogger = logrus.WithFields(logrus.Fields{
		"app":       "openmatch",
		"component": "backend",
	})
)

// RunApplication creates a server.
func RunApplication() {
	cfg, err := config.Read()
	if err != nil {
		mmlogicLogger.WithFields(logrus.Fields{
			"error": err.Error(),
		}).Fatalf("cannot read configuration.")
	}
	p, err := serving.NewParamsFromConfig(cfg, "api.mmlogic")
	if err != nil {
		mmlogicLogger.WithFields(logrus.Fields{
			"error": err.Error(),
		}).Fatalf("cannot construct server.")
	}

	BindService(p)
	serving.MustServeForever(p)
}

// BindService creates the mmlogic service to the server Params.
func BindService(p *serving.Params) {
	service := &mmlogicService{}
	p.AddHandleFunc(func(s *grpc.Server) {
		pb.RegisterMmLogicServer(s, service)
	}, pb.RegisterMmLogicHandlerFromEndpoint)
}
<|endoftext|>


<commit_before>package protocol

import "time"

// MaxPacketSizeIPv4 is the maximum packet size that we use for sending IPv4 packets.
const MaxPacketSizeIPv4 = 1252

// MaxPacketSizeIPv6 is the maximum packet size that we use for sending IPv6 packets.
const MaxPacketSizeIPv6 = 1232

// NonForwardSecurePacketSizeReduction is the number of bytes a non forward-secure packet has to be smaller than a forward-secure packet
// This makes sure that those packets can always be retransmitted without splitting the contained StreamFrames
const NonForwardSecurePacketSizeReduction = 50

const defaultMaxCongestionWindowPackets = 1000

// DefaultMaxCongestionWindow is the default for the max congestion window
const DefaultMaxCongestionWindow ByteCount = defaultMaxCongestionWindowPackets * DefaultTCPMSS

// InitialCongestionWindow is the initial congestion window in QUIC packets
const InitialCongestionWindow ByteCount = 32 * DefaultTCPMSS

// MaxUndecryptablePackets limits the number of undecryptable packets that a
// session queues for later until it sends a public reset.
const MaxUndecryptablePackets = 10

// ConnectionFlowControlMultiplier determines how much larger the connection flow control windows needs to be relative to any stream's flow control window
// This is the value that Chromium is using
const ConnectionFlowControlMultiplier = 1.5

// InitialMaxStreamData is the stream-level flow control window for receiving data
const InitialMaxStreamData = (1 << 10) * 512 // 512 kb

// InitialMaxData is the connection-level flow control window for receiving data
const InitialMaxData = ConnectionFlowControlMultiplier * InitialMaxStreamData

// DefaultMaxReceiveStreamFlowControlWindow is the default maximum stream-level flow control window for receiving data, for the server
const DefaultMaxReceiveStreamFlowControlWindow = 6 * (1 << 20) // 6 MB

// DefaultMaxReceiveConnectionFlowControlWindow is the default connection-level flow control window for receiving data, for the server
const DefaultMaxReceiveConnectionFlowControlWindow = 15 * (1 << 20) // 12 MB

// WindowUpdateThreshold is the fraction of the receive window that has to be consumed before an higher offset is advertised to the client
const WindowUpdateThreshold = 0.25

// DefaultMaxIncomingStreams is the maximum number of streams that a peer may open
const DefaultMaxIncomingStreams = 100

// DefaultMaxIncomingUniStreams is the maximum number of unidirectional streams that a peer may open
const DefaultMaxIncomingUniStreams = 100

// MaxSessionUnprocessedPackets is the max number of packets stored in each session that are not yet processed.
const MaxSessionUnprocessedPackets = defaultMaxCongestionWindowPackets

// SkipPacketAveragePeriodLength is the average period length in which one packet number is skipped to prevent an Optimistic ACK attack
const SkipPacketAveragePeriodLength PacketNumber = 500

// MaxTrackedSkippedPackets is the maximum number of skipped packet numbers the SentPacketHandler keep track of for Optimistic ACK attack mitigation
const MaxTrackedSkippedPackets = 10

// CookieExpiryTime is the valid time of a cookie
const CookieExpiryTime = 24 * time.Hour

// MaxOutstandingSentPackets is maximum number of packets saved for retransmission.
// When reached, it imposes a soft limit on sending new packets:
// Sending ACKs and retransmission is still allowed, but now new regular packets can be sent.
const MaxOutstandingSentPackets = 2 * defaultMaxCongestionWindowPackets

// MaxTrackedSentPackets is maximum number of sent packets saved for retransmission.
// When reached, no more packets will be sent.
// This value *must* be larger than MaxOutstandingSentPackets.
const MaxTrackedSentPackets = MaxOutstandingSentPackets * 5 / 4

// MaxTrackedReceivedAckRanges is the maximum number of ACK ranges tracked
const MaxTrackedReceivedAckRanges = defaultMaxCongestionWindowPackets

// MaxNonRetransmittableAcks is the maximum number of packets containing an ACK, but no retransmittable frames, that we send in a row
const MaxNonRetransmittableAcks = 19

// MaxStreamFrameSorterGaps is the maximum number of gaps between received StreamFrames
// prevents DoS attacks against the streamFrameSorter
const MaxStreamFrameSorterGaps = 1000

// MaxCryptoStreamOffset is the maximum offset allowed on any of the crypto streams.
// This limits the size of the ClientHello and Certificates that can be received.
const MaxCryptoStreamOffset = 16 * (1 << 10)

// MinRemoteIdleTimeout is the minimum value that we accept for the remote idle timeout
const MinRemoteIdleTimeout = 5 * time.Second

// DefaultIdleTimeout is the default idle timeout
const DefaultIdleTimeout = 30 * time.Second

// DefaultHandshakeTimeout is the default timeout for a connection until the crypto handshake succeeds.
const DefaultHandshakeTimeout = 10 * time.Second

// RetiredConnectionIDDeleteTimeout is the time we keep closed sessions around in order to retransmit the CONNECTION_CLOSE.
// after this time all information about the old connection will be deleted
const RetiredConnectionIDDeleteTimeout = time.Minute

// MinStreamFrameSize is the minimum size that has to be left in a packet, so that we add another STREAM frame.
// This avoids splitting up STREAM frames into small pieces, which has 2 advantages:
// 1. it reduces the framing overhead
// 2. it reduces the head-of-line blocking, when a packet is lost
const MinStreamFrameSize ByteCount = 128

// MaxAckFrameSize is the maximum size for an ACK frame that we write
// Due to the varint encoding, ACK frames can grow (almost) indefinitely large.
// The MaxAckFrameSize should be large enough to encode many ACK range,
// but must ensure that a maximum size ACK frame fits into one packet.
const MaxAckFrameSize ByteCount = 1000

// MinPacingDelay is the minimum duration that is used for packet pacing
// If the packet packing frequency is higher, multiple packets might be sent at once.
// Example: For a packet pacing delay of 20 microseconds, we would send 5 packets at once, wait for 100 microseconds, and so forth.
const MinPacingDelay time.Duration = 100 * time.Microsecond

// DefaultConnectionIDLength is the connection ID length that is used for multiplexed connections
// if no other value is configured.
const DefaultConnectionIDLength = 4
<commit_msg>reduce the duration we keep the mapping for retired connection IDs alive<commit_after>package protocol

import "time"

// MaxPacketSizeIPv4 is the maximum packet size that we use for sending IPv4 packets.
const MaxPacketSizeIPv4 = 1252

// MaxPacketSizeIPv6 is the maximum packet size that we use for sending IPv6 packets.
const MaxPacketSizeIPv6 = 1232

// NonForwardSecurePacketSizeReduction is the number of bytes a non forward-secure packet has to be smaller than a forward-secure packet
// This makes sure that those packets can always be retransmitted without splitting the contained StreamFrames
const NonForwardSecurePacketSizeReduction = 50

const defaultMaxCongestionWindowPackets = 1000

// DefaultMaxCongestionWindow is the default for the max congestion window
const DefaultMaxCongestionWindow ByteCount = defaultMaxCongestionWindowPackets * DefaultTCPMSS

// InitialCongestionWindow is the initial congestion window in QUIC packets
const InitialCongestionWindow ByteCount = 32 * DefaultTCPMSS

// MaxUndecryptablePackets limits the number of undecryptable packets that a
// session queues for later until it sends a public reset.
const MaxUndecryptablePackets = 10

// ConnectionFlowControlMultiplier determines how much larger the connection flow control windows needs to be relative to any stream's flow control window
// This is the value that Chromium is using
const ConnectionFlowControlMultiplier = 1.5

// InitialMaxStreamData is the stream-level flow control window for receiving data
const InitialMaxStreamData = (1 << 10) * 512 // 512 kb

// InitialMaxData is the connection-level flow control window for receiving data
const InitialMaxData = ConnectionFlowControlMultiplier * InitialMaxStreamData

// DefaultMaxReceiveStreamFlowControlWindow is the default maximum stream-level flow control window for receiving data, for the server
const DefaultMaxReceiveStreamFlowControlWindow = 6 * (1 << 20) // 6 MB

// DefaultMaxReceiveConnectionFlowControlWindow is the default connection-level flow control window for receiving data, for the server
const DefaultMaxReceiveConnectionFlowControlWindow = 15 * (1 << 20) // 12 MB

// WindowUpdateThreshold is the fraction of the receive window that has to be consumed before an higher offset is advertised to the client
const WindowUpdateThreshold = 0.25

// DefaultMaxIncomingStreams is the maximum number of streams that a peer may open
const DefaultMaxIncomingStreams = 100

// DefaultMaxIncomingUniStreams is the maximum number of unidirectional streams that a peer may open
const DefaultMaxIncomingUniStreams = 100

// MaxSessionUnprocessedPackets is the max number of packets stored in each session that are not yet processed.
const MaxSessionUnprocessedPackets = defaultMaxCongestionWindowPackets

// SkipPacketAveragePeriodLength is the average period length in which one packet number is skipped to prevent an Optimistic ACK attack
const SkipPacketAveragePeriodLength PacketNumber = 500

// MaxTrackedSkippedPackets is the maximum number of skipped packet numbers the SentPacketHandler keep track of for Optimistic ACK attack mitigation
const MaxTrackedSkippedPackets = 10

// CookieExpiryTime is the valid time of a cookie
const CookieExpiryTime = 24 * time.Hour

// MaxOutstandingSentPackets is maximum number of packets saved for retransmission.
// When reached, it imposes a soft limit on sending new packets:
// Sending ACKs and retransmission is still allowed, but now new regular packets can be sent.
const MaxOutstandingSentPackets = 2 * defaultMaxCongestionWindowPackets

// MaxTrackedSentPackets is maximum number of sent packets saved for retransmission.
// When reached, no more packets will be sent.
// This value *must* be larger than MaxOutstandingSentPackets.
const MaxTrackedSentPackets = MaxOutstandingSentPackets * 5 / 4

// MaxTrackedReceivedAckRanges is the maximum number of ACK ranges tracked
const MaxTrackedReceivedAckRanges = defaultMaxCongestionWindowPackets

// MaxNonRetransmittableAcks is the maximum number of packets containing an ACK, but no retransmittable frames, that we send in a row
const MaxNonRetransmittableAcks = 19

// MaxStreamFrameSorterGaps is the maximum number of gaps between received StreamFrames
// prevents DoS attacks against the streamFrameSorter
const MaxStreamFrameSorterGaps = 1000

// MaxCryptoStreamOffset is the maximum offset allowed on any of the crypto streams.
// This limits the size of the ClientHello and Certificates that can be received.
const MaxCryptoStreamOffset = 16 * (1 << 10)

// MinRemoteIdleTimeout is the minimum value that we accept for the remote idle timeout
const MinRemoteIdleTimeout = 5 * time.Second

// DefaultIdleTimeout is the default idle timeout
const DefaultIdleTimeout = 30 * time.Second

// DefaultHandshakeTimeout is the default timeout for a connection until the crypto handshake succeeds.
const DefaultHandshakeTimeout = 10 * time.Second

// RetiredConnectionIDDeleteTimeout is the time we keep closed sessions around in order to retransmit the CONNECTION_CLOSE.
// after this time all information about the old connection will be deleted
const RetiredConnectionIDDeleteTimeout = 5 * time.Second

// MinStreamFrameSize is the minimum size that has to be left in a packet, so that we add another STREAM frame.
// This avoids splitting up STREAM frames into small pieces, which has 2 advantages:
// 1. it reduces the framing overhead
// 2. it reduces the head-of-line blocking, when a packet is lost
const MinStreamFrameSize ByteCount = 128

// MaxAckFrameSize is the maximum size for an ACK frame that we write
// Due to the varint encoding, ACK frames can grow (almost) indefinitely large.
// The MaxAckFrameSize should be large enough to encode many ACK range,
// but must ensure that a maximum size ACK frame fits into one packet.
const MaxAckFrameSize ByteCount = 1000

// MinPacingDelay is the minimum duration that is used for packet pacing
// If the packet packing frequency is higher, multiple packets might be sent at once.
// Example: For a packet pacing delay of 20 microseconds, we would send 5 packets at once, wait for 100 microseconds, and so forth.
const MinPacingDelay time.Duration = 100 * time.Microsecond

// DefaultConnectionIDLength is the connection ID length that is used for multiplexed connections
// if no other value is configured.
const DefaultConnectionIDLength = 4
<|endoftext|>


<commit_before>package database

import (
	"encoding/binary"
	"encoding/json"
	"fmt"
	"os"

	"github.com/boltdb/bolt"
	"github.com/darwinfroese/hacksite/server/models"
	"github.com/darwinfroese/hacksite/server/utilities"
)

var projectBucket = []byte("projects")

// TODO: Need to limit the amount of operations and logic
// in the database code

// CreateBoltDB creates a basic database struct
func createBoltDB() Database {
	db := boltDB{
		dbLocation: "database.db",
	}

	createBuckets(db)
	return &db
}

func createBuckets(b boltDB) {
	db, err := bolt.Open(b.dbLocation, 0644, nil)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
		return
	}
	defer db.Close()

	err = db.Update(func(tx *bolt.Tx) error {
		_, err := tx.CreateBucketIfNotExists(projectBucket)
		if err != nil {
			return err
		}

		return nil
	})

	// TODO: This should probably crash the program? or attempt to recover?
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
	}
}

// AddProject will add a project to the database
func (b *boltDB) AddProject(project models.Project) (models.Project, error) {
	db, err := bolt.Open(b.dbLocation, 0644, nil)
	if err != nil {
		return models.Project{}, err
	}
	defer db.Close()

	project.Status = utilities.UpdateProjectStatus(project)

	err = db.Update(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(projectBucket)
		if bucket == nil {
			return fmt.Errorf("Bucket %q not found.", projectBucket)
		}

		id, err := bucket.NextSequence()
		if err != nil {
			return err
		}

		project.ID = int(id)
		project.CurrentIteration.ProjectID = project.ID
		project.CurrentIteration.Number = 1
		project.Iterations = append(project.Iterations, project.CurrentIteration)
		for i, task := range project.CurrentIteration.Tasks {
			task.ProjectID = project.ID
			task.IterationNumber = project.CurrentIteration.Number
			project.CurrentIteration.Tasks[i] = task
		}

		key := itob(int(id))
		value, err := json.Marshal(project)

		if err != nil {
			return err
		}

		return bucket.Put(key, value)
	})

	return project, nil
}

// GetProject will lookup a project by id
func (b *boltDB) GetProject(id int) (models.Project, error) {
	db, err := bolt.Open(b.dbLocation, 0644, nil)
	if err != nil {
		return models.Project{}, err
	}
	defer db.Close()

	var project models.Project
	err = db.View(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(projectBucket)
		if bucket == nil {
			return fmt.Errorf("Bucket %q not found.", projectBucket)
		}

		v := bucket.Get(itob(id))
		err := json.Unmarshal(v, &project)
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		return models.Project{}, err
	}

	return project, nil
}

// GetProjects will return all the projects in the database
func (b *boltDB) GetProjects() ([]models.Project, error) {
	db, err := bolt.Open(b.dbLocation, 0644, nil)
	if err != nil {
		return nil, err
	}
	defer db.Close()

	var projects []models.Project
	err = db.View(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(projectBucket)
		if bucket == nil {
			return fmt.Errorf("Bucket %q not found.", projectBucket)
		}

		c := bucket.Cursor()
		for k, v := c.First(); k != nil; k, v = c.Next() {
			var project models.Project
			err = json.Unmarshal(v, &project)

			if err != nil {
				return err
			}
			projects = append(projects, project)
		}

		return nil
	})

	if err != nil {
		return nil, err
	}

	return projects, nil
}

// UpdateProject will store the new project in the database
func (b *boltDB) UpdateProject(p models.Project) error {
	db, err := bolt.Open(b.dbLocation, 0644, nil)
	if err != nil {
		return err
	}
	defer db.Close()

	p.Status = utilities.UpdateProjectStatus(p)

	return db.Update(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(projectBucket)
		if bucket == nil {
			return fmt.Errorf("Bucket %q not found.", projectBucket)
		}

		v, err := json.Marshal(p)
		if err != nil {
			return err
		}

		err = bucket.Put(itob(p.ID), v)
		if err != nil {
			return err
		}

		return nil
	})
}

// UpdateTask will update a specfic task in a project
func (b *boltDB) UpdateTask(t models.Task) (models.Project, error) {
	db, err := bolt.Open(b.dbLocation, 0644, nil)
	if err != nil {
		return models.Project{}, err
	}
	defer db.Close()

	var project models.Project
	err = db.Update(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(projectBucket)
		if bucket == nil {
			return fmt.Errorf("Bucket %q not found.", projectBucket)
		}

		val := bucket.Get(itob(t.ProjectID))
		err := json.Unmarshal(val, &project)
		if err != nil {
			return err
		}

		tasks := project.CurrentIteration.Tasks

		for i, task := range tasks {
			if task.ID == t.ID {
				tasks[i] = t
				break
			}
		}

		project.CurrentIteration.Tasks = tasks
		for i, iter := range project.Iterations {
			if iter.Number == project.CurrentIteration.Number {
				project.Iterations[i] = project.CurrentIteration
			}
		}

		project.Status = utilities.UpdateProjectStatus(project)

		v, err := json.Marshal(project)
		if err != nil {
			return err
		}

		err = bucket.Put(itob(t.ProjectID), v)
		if err != nil {
			return err
		}

		return nil
	})

	return project, nil
}

// RemoveProject will remove a project from the database
func (b *boltDB) RemoveProject(id int) error {
	db, err := bolt.Open(b.dbLocation, 0644, nil)
	if err != nil {
		return err
	}
	defer db.Close()

	return db.Update(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(projectBucket)
		if bucket == nil {
			return fmt.Errorf("Bucket %q not found.", projectBucket)
		}

		err := bucket.Delete(itob(id))
		if err != nil {
			return err
		}

		return nil
	})
}

// RemoveTask will remove a task from a project
func (b *boltDB) RemoveTask(t models.Task) (models.Project, error) {
	db, err := bolt.Open(b.dbLocation, 0644, nil)
	if err != nil {
		return models.Project{}, err
	}
	defer db.Close()

	var project models.Project
	err = db.Update(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(projectBucket)
		if bucket == nil {
			return fmt.Errorf("Bucket %q not found.", projectBucket)
		}

		val := bucket.Get(itob(t.ProjectID))

		err := json.Unmarshal(val, &project)
		if err != nil {
			return err
		}

		tasks := project.CurrentIteration.Tasks

		for i, task := range tasks {
			if task.ID == t.ID {
				tasks = append(tasks[:i], tasks[i+1:]...)
				break
			}
		}

		project.CurrentIteration.Tasks = tasks
		for i, iter := range project.Iterations {
			if iter.Number == project.CurrentIteration.Number {
				project.Iterations[i] = project.CurrentIteration
			}
		}

		p, err := json.Marshal(project)
		if err != nil {
			return err
		}

		err = bucket.Put(itob(t.ProjectID), p)
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		return models.Project{}, err
	}

	return project, nil
}

// AddIteration will add an iteration to the project and update it in the database
func (b *boltDB) AddIteration(iteration models.Iteration) (models.Project, error) {
	db, err := bolt.Open(b.dbLocation, 0644, nil)
	if err != nil {
		return models.Project{}, err
	}
	defer db.Close()

	var project models.Project
	err = db.Update(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(projectBucket)
		if bucket == nil {
			return fmt.Errorf("Bucket %q not found.", projectBucket)
		}

		val := bucket.Get(itob(iteration.ProjectID))

		err := json.Unmarshal(val, &project)
		if err != nil {
			return err
		}

		project.CurrentIteration = iteration
		project.Iterations = append(project.Iterations, iteration)
		project.Status = utilities.UpdateProjectStatus(project)

		p, err := json.Marshal(project)
		if err != nil {
			return err
		}

		err = bucket.Put(itob(iteration.ProjectID), p)
		if err != nil {
			return err
		}

		return nil
	})

	if err != nil {
		return models.Project{}, err
	}

	return project, nil
}

// SwapCurrentIteration will set the iteration in the argument as the current iteration
func (b *boltDB) SwapCurrentIteration(iteration models.Iteration) (models.Project, error) {
	db, err := bolt.Open(b.dbLocation, 0644, nil)
	if err != nil {
		return models.Project{}, err
	}
	defer db.Close()

	var project models.Project
	err = db.Update(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(projectBucket)
		if bucket == nil {
			return fmt.Errorf("Bucket %q not found.", projectBucket)
		}

		val := bucket.Get(itob(iteration.ProjectID))

		err := json.Unmarshal(val, &project)
		if err != nil {
			return err
		}

		project.CurrentIteration = iteration
		project.Status = utilities.UpdateProjectStatus(project)

		p, err := json.Marshal(project)
		if err != nil {
			return err
		}

		err = bucket.Put(itob(iteration.ProjectID), p)
		if err != nil {
			return err
		}

		return nil
	})

	if err != nil {
		return models.Project{}, err
	}

	return project, nil
}

func itob(v int) []byte {
	b := make([]byte, 8)
	binary.BigEndian.PutUint64(b, uint64(v))
	return b
}
<commit_msg>added users bucket to database<commit_after>package database

import (
	"encoding/binary"
	"encoding/json"
	"fmt"
	"os"

	"github.com/boltdb/bolt"
	"github.com/darwinfroese/hacksite/server/models"
	"github.com/darwinfroese/hacksite/server/utilities"
)

var projectsBucket = []byte("projects")
var usersBucket = []byte("users")

// TODO: Need to limit the amount of operations and logic
// in the database code

// CreateBoltDB creates a basic database struct
func createBoltDB() Database {
	db := boltDB{
		dbLocation: "database.db",
	}

	createBuckets(db)
	return &db
}

func createBuckets(b boltDB) {
	db, err := bolt.Open(b.dbLocation, 0644, nil)
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
		return
	}
	defer db.Close()

	err = db.Update(func(tx *bolt.Tx) error {
		_, err := tx.CreateBucketIfNotExists(projectsBucket)
		if err != nil {
			return err
		}

		_, err = tx.CreateBucketIfNotExists(usersBucket)
		if err != nil {
			return err
		}

		return nil
	})

	// TODO: This should probably crash the program? or attempt to recover?
	if err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
	}
}

// AddProject will add a project to the database
func (b *boltDB) AddProject(project models.Project) (models.Project, error) {
	db, err := bolt.Open(b.dbLocation, 0644, nil)
	if err != nil {
		return models.Project{}, err
	}
	defer db.Close()

	project.Status = utilities.UpdateProjectStatus(project)

	err = db.Update(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(projectsBucket)
		if bucket == nil {
			return fmt.Errorf("Bucket %q not found.", projectsBucket)
		}

		id, err := bucket.NextSequence()
		if err != nil {
			return err
		}

		project.ID = int(id)
		project.CurrentIteration.ProjectID = project.ID
		project.CurrentIteration.Number = 1
		project.Iterations = append(project.Iterations, project.CurrentIteration)
		for i, task := range project.CurrentIteration.Tasks {
			task.ProjectID = project.ID
			task.IterationNumber = project.CurrentIteration.Number
			project.CurrentIteration.Tasks[i] = task
		}

		key := itob(int(id))
		value, err := json.Marshal(project)

		if err != nil {
			return err
		}

		return bucket.Put(key, value)
	})

	return project, nil
}

// GetProject will lookup a project by id
func (b *boltDB) GetProject(id int) (models.Project, error) {
	db, err := bolt.Open(b.dbLocation, 0644, nil)
	if err != nil {
		return models.Project{}, err
	}
	defer db.Close()

	var project models.Project
	err = db.View(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(projectsBucket)
		if bucket == nil {
			return fmt.Errorf("Bucket %q not found.", projectsBucket)
		}

		v := bucket.Get(itob(id))
		err := json.Unmarshal(v, &project)
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		return models.Project{}, err
	}

	return project, nil
}

// GetProjects will return all the projects in the database
func (b *boltDB) GetProjects() ([]models.Project, error) {
	db, err := bolt.Open(b.dbLocation, 0644, nil)
	if err != nil {
		return nil, err
	}
	defer db.Close()

	var projects []models.Project
	err = db.View(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(projectsBucket)
		if bucket == nil {
			return fmt.Errorf("Bucket %q not found.", projectsBucket)
		}

		c := bucket.Cursor()
		for k, v := c.First(); k != nil; k, v = c.Next() {
			var project models.Project
			err = json.Unmarshal(v, &project)

			if err != nil {
				return err
			}
			projects = append(projects, project)
		}

		return nil
	})

	if err != nil {
		return nil, err
	}

	return projects, nil
}

// UpdateProject will store the new project in the database
func (b *boltDB) UpdateProject(p models.Project) error {
	db, err := bolt.Open(b.dbLocation, 0644, nil)
	if err != nil {
		return err
	}
	defer db.Close()

	p.Status = utilities.UpdateProjectStatus(p)

	return db.Update(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(projectsBucket)
		if bucket == nil {
			return fmt.Errorf("Bucket %q not found.", projectsBucket)
		}

		v, err := json.Marshal(p)
		if err != nil {
			return err
		}

		err = bucket.Put(itob(p.ID), v)
		if err != nil {
			return err
		}

		return nil
	})
}

// UpdateTask will update a specfic task in a project
func (b *boltDB) UpdateTask(t models.Task) (models.Project, error) {
	db, err := bolt.Open(b.dbLocation, 0644, nil)
	if err != nil {
		return models.Project{}, err
	}
	defer db.Close()

	var project models.Project
	err = db.Update(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(projectsBucket)
		if bucket == nil {
			return fmt.Errorf("Bucket %q not found.", projectsBucket)
		}

		val := bucket.Get(itob(t.ProjectID))
		err := json.Unmarshal(val, &project)
		if err != nil {
			return err
		}

		tasks := project.CurrentIteration.Tasks

		for i, task := range tasks {
			if task.ID == t.ID {
				tasks[i] = t
				break
			}
		}

		project.CurrentIteration.Tasks = tasks
		for i, iter := range project.Iterations {
			if iter.Number == project.CurrentIteration.Number {
				project.Iterations[i] = project.CurrentIteration
			}
		}

		project.Status = utilities.UpdateProjectStatus(project)

		v, err := json.Marshal(project)
		if err != nil {
			return err
		}

		err = bucket.Put(itob(t.ProjectID), v)
		if err != nil {
			return err
		}

		return nil
	})

	return project, nil
}

// RemoveProject will remove a project from the database
func (b *boltDB) RemoveProject(id int) error {
	db, err := bolt.Open(b.dbLocation, 0644, nil)
	if err != nil {
		return err
	}
	defer db.Close()

	return db.Update(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(projectsBucket)
		if bucket == nil {
			return fmt.Errorf("Bucket %q not found.", projectsBucket)
		}

		err := bucket.Delete(itob(id))
		if err != nil {
			return err
		}

		return nil
	})
}

// RemoveTask will remove a task from a project
func (b *boltDB) RemoveTask(t models.Task) (models.Project, error) {
	db, err := bolt.Open(b.dbLocation, 0644, nil)
	if err != nil {
		return models.Project{}, err
	}
	defer db.Close()

	var project models.Project
	err = db.Update(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(projectsBucket)
		if bucket == nil {
			return fmt.Errorf("Bucket %q not found.", projectsBucket)
		}

		val := bucket.Get(itob(t.ProjectID))

		err := json.Unmarshal(val, &project)
		if err != nil {
			return err
		}

		tasks := project.CurrentIteration.Tasks

		for i, task := range tasks {
			if task.ID == t.ID {
				tasks = append(tasks[:i], tasks[i+1:]...)
				break
			}
		}

		project.CurrentIteration.Tasks = tasks
		for i, iter := range project.Iterations {
			if iter.Number == project.CurrentIteration.Number {
				project.Iterations[i] = project.CurrentIteration
			}
		}

		p, err := json.Marshal(project)
		if err != nil {
			return err
		}

		err = bucket.Put(itob(t.ProjectID), p)
		if err != nil {
			return err
		}

		return nil
	})
	if err != nil {
		return models.Project{}, err
	}

	return project, nil
}

// AddIteration will add an iteration to the project and update it in the database
func (b *boltDB) AddIteration(iteration models.Iteration) (models.Project, error) {
	db, err := bolt.Open(b.dbLocation, 0644, nil)
	if err != nil {
		return models.Project{}, err
	}
	defer db.Close()

	var project models.Project
	err = db.Update(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(projectsBucket)
		if bucket == nil {
			return fmt.Errorf("Bucket %q not found.", projectsBucket)
		}

		val := bucket.Get(itob(iteration.ProjectID))

		err := json.Unmarshal(val, &project)
		if err != nil {
			return err
		}

		project.CurrentIteration = iteration
		project.Iterations = append(project.Iterations, iteration)
		project.Status = utilities.UpdateProjectStatus(project)

		p, err := json.Marshal(project)
		if err != nil {
			return err
		}

		err = bucket.Put(itob(iteration.ProjectID), p)
		if err != nil {
			return err
		}

		return nil
	})

	if err != nil {
		return models.Project{}, err
	}

	return project, nil
}

// SwapCurrentIteration will set the iteration in the argument as the current iteration
func (b *boltDB) SwapCurrentIteration(iteration models.Iteration) (models.Project, error) {
	db, err := bolt.Open(b.dbLocation, 0644, nil)
	if err != nil {
		return models.Project{}, err
	}
	defer db.Close()

	var project models.Project
	err = db.Update(func(tx *bolt.Tx) error {
		bucket := tx.Bucket(projectsBucket)
		if bucket == nil {
			return fmt.Errorf("Bucket %q not found.", projectsBucket)
		}

		val := bucket.Get(itob(iteration.ProjectID))

		err := json.Unmarshal(val, &project)
		if err != nil {
			return err
		}

		project.CurrentIteration = iteration
		project.Status = utilities.UpdateProjectStatus(project)

		p, err := json.Marshal(project)
		if err != nil {
			return err
		}

		err = bucket.Put(itob(iteration.ProjectID), p)
		if err != nil {
			return err
		}

		return nil
	})

	if err != nil {
		return models.Project{}, err
	}

	return project, nil
}

func itob(v int) []byte {
	b := make([]byte, 8)
	binary.BigEndian.PutUint64(b, uint64(v))
	return b
}
<|endoftext|>


<commit_before>package server

import (
	"context"
	"fmt"
	"net"
	"strings"

	cnitypes "github.com/containernetworking/cni/pkg/types"
	cnicurrent "github.com/containernetworking/cni/pkg/types/current"
	"github.com/cri-o/cri-o/internal/lib/sandbox"
	"github.com/cri-o/cri-o/internal/pkg/log"
	"k8s.io/kubernetes/pkg/kubelet/dockershim/network/hostport"
)

// networkStart sets up the sandbox's network and returns the pod IP on success
// or an error
func (s *Server) networkStart(ctx context.Context, sb *sandbox.Sandbox) (podIPs []string, result cnitypes.Result, err error) {
	if sb.HostNetwork() {
		return []string{s.hostIP}, nil, nil
	}

	podNetwork, err := s.newPodNetwork(sb)
	if err != nil {
		return
	}

	// Ensure network resources are cleaned up if the plugin succeeded
	// but an error happened between plugin success and the end of networkStart()
	defer func() {
		if err != nil {
			s.networkStop(ctx, sb)
		}
	}()

	_, err = s.netPlugin.SetUpPod(podNetwork)
	if err != nil {
		err = fmt.Errorf("failed to create pod network sandbox %s(%s): %v", sb.Name(), sb.ID(), err)
		return
	}

	tmp, err := s.netPlugin.GetPodNetworkStatus(podNetwork)
	if err != nil {
		err = fmt.Errorf("failed to get network status for pod sandbox %s(%s): %v", sb.Name(), sb.ID(), err)
		return
	}

	// only one cnitypes.Result is returned since newPodNetwork sets Networks list empty
	result = tmp[0]
	log.Debugf(ctx, "CNI setup result: %v", result)

	network, err := cnicurrent.GetResult(result)
	if err != nil {
		err = fmt.Errorf("failed to get network JSON for pod sandbox %s(%s): %v", sb.Name(), sb.ID(), err)
		return
	}

	for idx, podIPConfig := range network.IPs {
		podIP := strings.Split(podIPConfig.Address.String(), "/")[0]

		// Apply the hostport mappings only for the first IP to avoid allocating
		// the same host port twice
		if idx == 0 && len(sb.PortMappings()) > 0 {
			ip := net.ParseIP(podIP)
			if ip == nil {
				err = fmt.Errorf("failed to get valid ip address for sandbox %s(%s)", sb.Name(), sb.ID())
				return
			}

			err = s.hostportManager.Add(sb.ID(), &hostport.PodPortMapping{
				Name:         sb.Name(),
				PortMappings: sb.PortMappings(),
				IP:           ip,
				HostNetwork:  false,
			}, "lo")
			if err != nil {
				err = fmt.Errorf("failed to add hostport mapping for sandbox %s(%s): %v", sb.Name(), sb.ID(), err)
				return
			}
		}

		podIPs = append(podIPs, podIP)
	}

	log.Debugf(ctx, "found POD IPs: %v", podIPs)
	return podIPs, result, err
}

// getSandboxIP retrieves the IP address for the sandbox
func (s *Server) getSandboxIPs(sb *sandbox.Sandbox) (podIPs []string, err error) {
	if sb.HostNetwork() {
		return []string{s.hostIP}, nil
	}

	podNetwork, err := s.newPodNetwork(sb)
	if err != nil {
		return nil, err
	}
	result, err := s.netPlugin.GetPodNetworkStatus(podNetwork)
	if err != nil {
		return nil, fmt.Errorf("failed to get network status for pod sandbox %s(%s): %v", sb.Name(), sb.ID(), err)
	}

	res, err := cnicurrent.GetResult(result[0])
	if err != nil {
		return nil, fmt.Errorf("failed to get network JSON for pod sandbox %s(%s): %v", sb.Name(), sb.ID(), err)
	}

	for _, podIPConfig := range res.IPs {
		podIPs = append(podIPs, strings.Split(podIPConfig.Address.String(), "/")[0])
	}

	return podIPs, nil
}

// networkStop cleans up and removes a pod's network.  It is best-effort and
// must call the network plugin even if the network namespace is already gone
func (s *Server) networkStop(ctx context.Context, sb *sandbox.Sandbox) {
	if sb.HostNetwork() {
		return
	}

	if err := s.hostportManager.Remove(sb.ID(), &hostport.PodPortMapping{
		Name:         sb.Name(),
		PortMappings: sb.PortMappings(),
		HostNetwork:  false,
	}); err != nil {
		log.Warnf(ctx, "failed to remove hostport for pod sandbox %s(%s): %v",
			sb.Name(), sb.ID(), err)
	}

	podNetwork, err := s.newPodNetwork(sb)
	if err != nil {
		log.Warnf(ctx, err.Error())
		return
	}
	if err := s.netPlugin.TearDownPod(podNetwork); err != nil {
		log.Warnf(ctx, "failed to destroy network for pod sandbox %s(%s): %v",
			sb.Name(), sb.ID(), err)
	}
}
<commit_msg>Fix hostport mapping for IPv6 addresses<commit_after>package server

import (
	"context"
	"fmt"
	"net"
	"strings"

	cnitypes "github.com/containernetworking/cni/pkg/types"
	cnicurrent "github.com/containernetworking/cni/pkg/types/current"
	"github.com/cri-o/cri-o/internal/lib/sandbox"
	"github.com/cri-o/cri-o/internal/pkg/log"
	"k8s.io/kubernetes/pkg/kubelet/dockershim/network/hostport"
)

// networkStart sets up the sandbox's network and returns the pod IP on success
// or an error
func (s *Server) networkStart(ctx context.Context, sb *sandbox.Sandbox) (podIPs []string, result cnitypes.Result, err error) {
	if sb.HostNetwork() {
		return []string{s.hostIP}, nil, nil
	}

	podNetwork, err := s.newPodNetwork(sb)
	if err != nil {
		return
	}

	// Ensure network resources are cleaned up if the plugin succeeded
	// but an error happened between plugin success and the end of networkStart()
	defer func() {
		if err != nil {
			s.networkStop(ctx, sb)
		}
	}()

	_, err = s.netPlugin.SetUpPod(podNetwork)
	if err != nil {
		err = fmt.Errorf("failed to create pod network sandbox %s(%s): %v", sb.Name(), sb.ID(), err)
		return
	}

	tmp, err := s.netPlugin.GetPodNetworkStatus(podNetwork)
	if err != nil {
		err = fmt.Errorf("failed to get network status for pod sandbox %s(%s): %v", sb.Name(), sb.ID(), err)
		return
	}

	// only one cnitypes.Result is returned since newPodNetwork sets Networks list empty
	result = tmp[0]
	log.Debugf(ctx, "CNI setup result: %v", result)

	network, err := cnicurrent.GetResult(result)
	if err != nil {
		err = fmt.Errorf("failed to get network JSON for pod sandbox %s(%s): %v", sb.Name(), sb.ID(), err)
		return
	}

	for idx, podIPConfig := range network.IPs {
		podIP := strings.Split(podIPConfig.Address.String(), "/")[0]

		// Apply the hostport mappings only for the first IP to avoid allocating
		// the same host port twice
		if idx == 0 && len(sb.PortMappings()) > 0 {
			ip := net.ParseIP(podIP)

			if ip.To4() == nil {
				// Skip IPv6 addresses since they're currently not supported by
				// the hostport manager. Beside this, it would not make much
				// sense to try to expose the same port twice in IPv6 dual
				// stack mode.
				continue
			}

			if ip == nil {
				err = fmt.Errorf("failed to get valid ip address for sandbox %s(%s)", sb.Name(), sb.ID())
				return
			}

			err = s.hostportManager.Add(sb.ID(), &hostport.PodPortMapping{
				Name:         sb.Name(),
				PortMappings: sb.PortMappings(),
				IP:           ip,
				HostNetwork:  false,
			}, "lo")
			if err != nil {
				err = fmt.Errorf("failed to add hostport mapping for sandbox %s(%s): %v", sb.Name(), sb.ID(), err)
				return
			}
		}

		podIPs = append(podIPs, podIP)
	}

	log.Debugf(ctx, "found POD IPs: %v", podIPs)
	return podIPs, result, err
}

// getSandboxIP retrieves the IP address for the sandbox
func (s *Server) getSandboxIPs(sb *sandbox.Sandbox) (podIPs []string, err error) {
	if sb.HostNetwork() {
		return []string{s.hostIP}, nil
	}

	podNetwork, err := s.newPodNetwork(sb)
	if err != nil {
		return nil, err
	}
	result, err := s.netPlugin.GetPodNetworkStatus(podNetwork)
	if err != nil {
		return nil, fmt.Errorf("failed to get network status for pod sandbox %s(%s): %v", sb.Name(), sb.ID(), err)
	}

	res, err := cnicurrent.GetResult(result[0])
	if err != nil {
		return nil, fmt.Errorf("failed to get network JSON for pod sandbox %s(%s): %v", sb.Name(), sb.ID(), err)
	}

	for _, podIPConfig := range res.IPs {
		podIPs = append(podIPs, strings.Split(podIPConfig.Address.String(), "/")[0])
	}

	return podIPs, nil
}

// networkStop cleans up and removes a pod's network.  It is best-effort and
// must call the network plugin even if the network namespace is already gone
func (s *Server) networkStop(ctx context.Context, sb *sandbox.Sandbox) {
	if sb.HostNetwork() {
		return
	}

	if err := s.hostportManager.Remove(sb.ID(), &hostport.PodPortMapping{
		Name:         sb.Name(),
		PortMappings: sb.PortMappings(),
		HostNetwork:  false,
	}); err != nil {
		log.Warnf(ctx, "failed to remove hostport for pod sandbox %s(%s): %v",
			sb.Name(), sb.ID(), err)
	}

	podNetwork, err := s.newPodNetwork(sb)
	if err != nil {
		log.Warnf(ctx, err.Error())
		return
	}
	if err := s.netPlugin.TearDownPod(podNetwork); err != nil {
		log.Warnf(ctx, "failed to destroy network for pod sandbox %s(%s): %v",
			sb.Name(), sb.ID(), err)
	}
}
<|endoftext|>


<commit_before>package fixchain

import (
	"net/http"
	"sync"
	"testing"

	"github.com/google/certificate-transparency/go/x509"
)

// NewFixer() test
func TestNewFixer(t *testing.T) {
	chains := make(chan []*x509.Certificate)
	errors := make(chan *FixError)

	var expectedChains [][]string
	var expectedErrs []errorType
	for _, test := range handleChainTests {
		expectedChains = append(expectedChains, test.expectedChains...)
		expectedErrs = append(expectedErrs, test.expectedErrs...)
	}

	var wg sync.WaitGroup
	wg.Add(2)
	go testChains(t, 0, expectedChains, chains, &wg)
	go testErrors(t, 0, expectedErrs, errors, &wg)

	f := NewFixer(10, chains, errors, &http.Client{Transport: &testRoundTripper{}}, false)
	for _, test := range handleChainTests {
		f.QueueChain(GetTestCertificateFromPEM(t, test.cert),
			extractTestChain(t, 0, test.chain), extractTestRoots(t, 0, test.roots))
	}
	f.Wait()

	close(chains)
	close(errors)
	wg.Wait()
}

// Fixer.fixServer() test
func TestFixServer(t *testing.T) {
	cache := &urlCache{cache: newLockedCache(), client: &http.Client{Transport: &testRoundTripper{}}}
	f := &Fixer{cache: cache}

	var wg sync.WaitGroup
	fixServerTests := handleChainTests

	// Pass chains to be fixed one at a time to fixServer and check the chain
	// and errors produced are correct.
	for i, fst := range fixServerTests {
		chains := make(chan []*x509.Certificate)
		errors := make(chan *FixError)
		f.toFix = make(chan *toFix)
		f.chains = chains
		f.errors = errors

		wg.Add(2)
		go testChains(t, i, fst.expectedChains, chains, &wg)
		go testErrors(t, i, fst.expectedErrs, errors, &wg)

		f.wg.Add(1)
		go f.fixServer()
		f.QueueChain(GetTestCertificateFromPEM(t, fst.cert),
			extractTestChain(t, i, fst.chain), extractTestRoots(t, i, fst.roots))
		f.Wait()

		close(chains)
		close(errors)
		wg.Wait()
	}

	// Pass multiple chains to be fixed to fixServer and check the chain and
	// errors produced are correct.
	chains := make(chan []*x509.Certificate)
	errors := make(chan *FixError)
	f.toFix = make(chan *toFix)
	f.chains = chains
	f.errors = errors

	var expectedChains [][]string
	var expectedErrs []errorType
	for _, fst := range fixServerTests {
		expectedChains = append(expectedChains, fst.expectedChains...)
		expectedErrs = append(expectedErrs, fst.expectedErrs...)
	}

	i := len(fixServerTests)
	wg.Add(2)
	go testChains(t, i, expectedChains, chains, &wg)
	go testErrors(t, i, expectedErrs, errors, &wg)

	f.wg.Add(1)
	go f.fixServer()
	for _, fst := range fixServerTests {
		f.QueueChain(GetTestCertificateFromPEM(t, fst.cert),
			extractTestChain(t, i, fst.chain), extractTestRoots(t, i, fst.roots))
	}
	f.Wait()

	close(chains)
	close(errors)
	wg.Wait()
}

func TestRemoveSuperChains(t *testing.T) {
	superChainsTests := []struct {
		chains         [][]string
		expectedChains [][]string
	}{
		{
			chains: [][]string{
				[]string{googleLeaf, thawteIntermediate},
				[]string{googleLeaf},
			},
			expectedChains: [][]string{
				[]string{"Google"},
			},
		},
		{
			chains: [][]string{
				[]string{googleLeaf, verisignRoot},
				[]string{googleLeaf, thawteIntermediate},
				[]string{googleLeaf},
			},
			expectedChains: [][]string{
				[]string{"Google"},
			},
		},
		{
			chains: [][]string{
				[]string{googleLeaf, thawteIntermediate, verisignRoot},
				[]string{googleLeaf, thawteIntermediate},
				[]string{googleLeaf},
			},
			expectedChains: [][]string{
				[]string{"Google"},
			},
		},
		{
			chains: [][]string{
				[]string{googleLeaf, thawteIntermediate, verisignRoot},
				[]string{googleLeaf},
			},
			expectedChains: [][]string{
				[]string{"Google"},
			},
		},
		{
			chains: [][]string{
				[]string{googleLeaf, thawteIntermediate, verisignRoot},
				[]string{googleLeaf, verisignRoot},
				[]string{googleLeaf, thawteIntermediate},
			},
			expectedChains: [][]string{
				[]string{"Google", "Thawte"},
				[]string{"Google", "VeriSign"},
			},
		},
		{
			chains: [][]string{
				[]string{testLeaf, testIntermediate2},
				[]string{googleLeaf, thawteIntermediate, verisignRoot},
				[]string{testLeaf, testIntermediate2, testIntermediate1, testRoot},
				[]string{googleLeaf, verisignRoot},
				[]string{testLeaf, testIntermediate2, testIntermediate1},
				[]string{googleLeaf, thawteIntermediate},
				[]string{testLeaf, googleLeaf, thawteIntermediate, verisignRoot},
			},
			expectedChains: [][]string{
				[]string{"Google", "Thawte"},
				[]string{"Google", "VeriSign"},
				[]string{"Leaf", "Intermediate2"},
				[]string{"Leaf", "Google", "Thawte", "VeriSign"},
			},
		},
	}

	for i, test := range superChainsTests {
		var chains [][]*x509.Certificate
		for _, chain := range test.chains {
			chains = append(chains, extractTestChain(t, i, chain))
		}
		matchTestChainList(t, i, test.expectedChains, removeSuperChains(chains))
	}
}

// Fixer.updateCounters() tests
func TestUpdateCounters(t *testing.T) {
	counterTests := []struct {
		errors           []errorType
		reconstructed    uint32
		notReconstructed uint32
		fixed            uint32
		notFixed         uint32
	}{
		{[]errorType{}, 1, 0, 0, 0},
		{[]errorType{VerifyFailed}, 0, 1, 1, 0},
		{[]errorType{VerifyFailed, FixFailed}, 0, 1, 0, 1},

		{[]errorType{ParseFailure}, 1, 0, 0, 0},
		{[]errorType{ParseFailure, VerifyFailed}, 0, 1, 1, 0},
		{[]errorType{ParseFailure, VerifyFailed, FixFailed}, 0, 1, 0, 1},
	}

	for i, test := range counterTests {
		f := &Fixer{}
		var ferrs []*FixError
		for _, err := range test.errors {
			ferrs = append(ferrs, &FixError{Type: err})
		}
		f.updateCounters(ferrs)

		if f.reconstructed != test.reconstructed {
			t.Errorf("#%d: Incorrect value for reconstructed, wanted %d, got %d", i, test.reconstructed, f.reconstructed)
		}
		if f.notReconstructed != test.notReconstructed {
			t.Errorf("#%d: Incorrect value for notReconstructed, wanted %d, got %d", i, test.notReconstructed, f.notReconstructed)
		}
		if f.fixed != test.fixed {
			t.Errorf("#%d: Incorrect value for fixed, wanted %d, got %d", i, test.fixed, f.fixed)
		}
		if f.notFixed != test.notFixed {
			t.Errorf("#%d: Incorrect value for notFixed, wanted %d, got %d", i, test.notFixed, f.notFixed)
		}
	}
}

// Fixer.QueueChain() tests
type fixerQueueTest struct {
	cert  string
	chain []string
	roots []string

	dchain []string
}

var fixerQueueTests = []fixerQueueTest{
	{
		cert:  googleLeaf,
		chain: []string{verisignRoot, thawteIntermediate},
		roots: []string{verisignRoot},

		dchain: []string{"VeriSign", "Thawte"},
	},
	{
		cert:  googleLeaf,
		chain: []string{verisignRoot, verisignRoot, thawteIntermediate},
		roots: []string{verisignRoot},

		dchain: []string{"VeriSign", "Thawte"},
	},
	{
		cert:  googleLeaf,
		roots: []string{verisignRoot},

		dchain: []string{},
	},
}

func testFixerQueueChain(t *testing.T, i int, qt *fixerQueueTest, f *Fixer) {
	defer f.wg.Done()
	fix := <-f.toFix
	// Check the deduped chain
	matchTestChain(t, i, qt.dchain, fix.chain.certs)
}

func TestFixerQueueChain(t *testing.T) {
	ch := make(chan *toFix)
	defer close(ch)
	f := &Fixer{toFix: ch}

	for i, qt := range fixerQueueTests {
		f.wg.Add(1)
		go testFixerQueueChain(t, i, &qt, f)
		chain := extractTestChain(t, i, qt.chain)
		roots := extractTestRoots(t, i, qt.roots)
		f.QueueChain(GetTestCertificateFromPEM(t, qt.cert), chain, roots)
		f.wg.Wait()
	}
}
<commit_msg>Fix bug in tests since logging changed<commit_after>package fixchain

import (
	"net/http"
	"sync"
	"testing"

	"github.com/google/certificate-transparency/go/x509"
)

// NewFixer() test
func TestNewFixer(t *testing.T) {
	chains := make(chan []*x509.Certificate)
	errors := make(chan *FixError)

	var expectedChains [][]string
	var expectedErrs []errorType
	for _, test := range handleChainTests {
		expectedChains = append(expectedChains, test.expectedChains...)
		expectedErrs = append(expectedErrs, test.expectedErrs...)
	}

	var wg sync.WaitGroup
	wg.Add(2)
	go testChains(t, 0, expectedChains, chains, &wg)
	go testErrors(t, 0, expectedErrs, errors, &wg)

	f := NewFixer(10, chains, errors, &http.Client{Transport: &testRoundTripper{}}, false)
	for _, test := range handleChainTests {
		f.QueueChain(GetTestCertificateFromPEM(t, test.cert),
			extractTestChain(t, 0, test.chain), extractTestRoots(t, 0, test.roots))
	}
	f.Wait()

	close(chains)
	close(errors)
	wg.Wait()
}

// Fixer.fixServer() test
func TestFixServer(t *testing.T) {
	cache := &urlCache{cache: newLockedCache(), client: &http.Client{Transport: &testRoundTripper{}}}
	f := &Fixer{cache: cache}

	var wg sync.WaitGroup
	fixServerTests := handleChainTests

	// Pass chains to be fixed one at a time to fixServer and check the chain
	// and errors produced are correct.
	for i, fst := range fixServerTests {
		chains := make(chan []*x509.Certificate)
		errors := make(chan *FixError)
		f.toFix = make(chan *toFix)
		f.chains = chains
		f.errors = errors

		wg.Add(2)
		go testChains(t, i, fst.expectedChains, chains, &wg)
		go testErrors(t, i, fst.expectedErrs, errors, &wg)

		f.wg.Add(1)
		go f.fixServer()
		f.QueueChain(GetTestCertificateFromPEM(t, fst.cert),
			extractTestChain(t, i, fst.chain), extractTestRoots(t, i, fst.roots))
		f.Wait()

		close(chains)
		close(errors)
		wg.Wait()
	}

	// Pass multiple chains to be fixed to fixServer and check the chain and
	// errors produced are correct.
	chains := make(chan []*x509.Certificate)
	errors := make(chan *FixError)
	f.toFix = make(chan *toFix)
	f.chains = chains
	f.errors = errors

	var expectedChains [][]string
	var expectedErrs []errorType
	for _, fst := range fixServerTests {
		expectedChains = append(expectedChains, fst.expectedChains...)
		expectedErrs = append(expectedErrs, fst.expectedErrs...)
	}

	i := len(fixServerTests)
	wg.Add(2)
	go testChains(t, i, expectedChains, chains, &wg)
	go testErrors(t, i, expectedErrs, errors, &wg)

	f.wg.Add(1)
	go f.fixServer()
	for _, fst := range fixServerTests {
		f.QueueChain(GetTestCertificateFromPEM(t, fst.cert),
			extractTestChain(t, i, fst.chain), extractTestRoots(t, i, fst.roots))
	}
	f.Wait()

	close(chains)
	close(errors)
	wg.Wait()
}

func TestRemoveSuperChains(t *testing.T) {
	superChainsTests := []struct {
		chains         [][]string
		expectedChains [][]string
	}{
		{
			chains: [][]string{
				[]string{googleLeaf, thawteIntermediate},
				[]string{googleLeaf},
			},
			expectedChains: [][]string{
				[]string{"Google"},
			},
		},
		{
			chains: [][]string{
				[]string{googleLeaf, verisignRoot},
				[]string{googleLeaf, thawteIntermediate},
				[]string{googleLeaf},
			},
			expectedChains: [][]string{
				[]string{"Google"},
			},
		},
		{
			chains: [][]string{
				[]string{googleLeaf, thawteIntermediate, verisignRoot},
				[]string{googleLeaf, thawteIntermediate},
				[]string{googleLeaf},
			},
			expectedChains: [][]string{
				[]string{"Google"},
			},
		},
		{
			chains: [][]string{
				[]string{googleLeaf, thawteIntermediate, verisignRoot},
				[]string{googleLeaf},
			},
			expectedChains: [][]string{
				[]string{"Google"},
			},
		},
		{
			chains: [][]string{
				[]string{googleLeaf, thawteIntermediate, verisignRoot},
				[]string{googleLeaf, verisignRoot},
				[]string{googleLeaf, thawteIntermediate},
			},
			expectedChains: [][]string{
				[]string{"Google", "Thawte"},
				[]string{"Google", "VeriSign"},
			},
		},
		{
			chains: [][]string{
				[]string{testLeaf, testIntermediate2},
				[]string{googleLeaf, thawteIntermediate, verisignRoot},
				[]string{testLeaf, testIntermediate2, testIntermediate1, testRoot},
				[]string{googleLeaf, verisignRoot},
				[]string{testLeaf, testIntermediate2, testIntermediate1},
				[]string{googleLeaf, thawteIntermediate},
				[]string{testLeaf, googleLeaf, thawteIntermediate, verisignRoot},
			},
			expectedChains: [][]string{
				[]string{"Google", "Thawte"},
				[]string{"Google", "VeriSign"},
				[]string{"Leaf", "Intermediate2"},
				[]string{"Leaf", "Google", "Thawte", "VeriSign"},
			},
		},
	}

	for i, test := range superChainsTests {
		var chains [][]*x509.Certificate
		for _, chain := range test.chains {
			chains = append(chains, extractTestChain(t, i, chain))
		}
		matchTestChainList(t, i, test.expectedChains, removeSuperChains(chains))
	}
}

// Fixer.updateCounters() tests
func TestUpdateCounters(t *testing.T) {
	counterTests := []struct {
		errors           []errorType
		reconstructed    uint32
		notReconstructed uint32
		fixed            uint32
		notFixed         uint32
	}{
		{[]errorType{}, 1, 0, 0, 0},
		{[]errorType{VerifyFailed}, 0, 1, 1, 0},
		{[]errorType{VerifyFailed, FixFailed}, 0, 1, 0, 1},

		{[]errorType{ParseFailure}, 1, 0, 0, 0},
		{[]errorType{ParseFailure, VerifyFailed}, 0, 1, 1, 0},
		{[]errorType{ParseFailure, VerifyFailed, FixFailed}, 0, 1, 0, 1},
	}

	for i, test := range counterTests {
		f := &Fixer{}
		var ferrs []*FixError
		for _, err := range test.errors {
			ferrs = append(ferrs, &FixError{Type: err})
		}
		f.updateCounters(nil, ferrs)

		if f.reconstructed != test.reconstructed {
			t.Errorf("#%d: Incorrect value for reconstructed, wanted %d, got %d", i, test.reconstructed, f.reconstructed)
		}
		if f.notReconstructed != test.notReconstructed {
			t.Errorf("#%d: Incorrect value for notReconstructed, wanted %d, got %d", i, test.notReconstructed, f.notReconstructed)
		}
		if f.fixed != test.fixed {
			t.Errorf("#%d: Incorrect value for fixed, wanted %d, got %d", i, test.fixed, f.fixed)
		}
		if f.notFixed != test.notFixed {
			t.Errorf("#%d: Incorrect value for notFixed, wanted %d, got %d", i, test.notFixed, f.notFixed)
		}
	}
}

// Fixer.QueueChain() tests
type fixerQueueTest struct {
	cert  string
	chain []string
	roots []string

	dchain []string
}

var fixerQueueTests = []fixerQueueTest{
	{
		cert:  googleLeaf,
		chain: []string{verisignRoot, thawteIntermediate},
		roots: []string{verisignRoot},

		dchain: []string{"VeriSign", "Thawte"},
	},
	{
		cert:  googleLeaf,
		chain: []string{verisignRoot, verisignRoot, thawteIntermediate},
		roots: []string{verisignRoot},

		dchain: []string{"VeriSign", "Thawte"},
	},
	{
		cert:  googleLeaf,
		roots: []string{verisignRoot},

		dchain: []string{},
	},
}

func testFixerQueueChain(t *testing.T, i int, qt *fixerQueueTest, f *Fixer) {
	defer f.wg.Done()
	fix := <-f.toFix
	// Check the deduped chain
	matchTestChain(t, i, qt.dchain, fix.chain.certs)
}

func TestFixerQueueChain(t *testing.T) {
	ch := make(chan *toFix)
	defer close(ch)
	f := &Fixer{toFix: ch}

	for i, qt := range fixerQueueTests {
		f.wg.Add(1)
		go testFixerQueueChain(t, i, &qt, f)
		chain := extractTestChain(t, i, qt.chain)
		roots := extractTestRoots(t, i, qt.roots)
		f.QueueChain(GetTestCertificateFromPEM(t, qt.cert), chain, roots)
		f.wg.Wait()
	}
}
<|endoftext|>


<commit_before>package posix

import (
	"fmt"
	"os"
	"syscall"

	co "github.com/lunixbochs/usercorn/go/kernel/common"
)

func (k *PosixKernel) Socket(domain, typ, protocol int) uint64 {
	fd, err := syscall.Socket(domain, typ, protocol)
	if err != nil {
		return Errno(err)
	}
	return uint64(fd)
}

func (k *PosixKernel) Connect(fd co.Fd, sa syscall.Sockaddr, size co.Len) uint64 {
	return Errno(syscall.Connect(int(fd), sa))
}

func (k *PosixKernel) Bind(fd co.Fd, sa syscall.Sockaddr, size co.Len) uint64 {
	return Errno(syscall.Bind(int(fd), sa))
}

func (k *PosixKernel) Sendto(fd co.Fd, buf co.Buf, size co.Len, flags int, sa syscall.Sockaddr, socklen co.Len) uint64 {
	msg := make([]byte, size)
	if err := buf.Unpack(msg); err != nil {
		return UINT64_MAX // FIXME
	}
	return Errno(syscall.Sendto(int(fd), msg, flags, sa))
}

func (k *PosixKernel) Getsockopt(fd co.Fd, level, opt int, valueOut, valueSizeOut co.Buf) uint64 {
	// TODO: dispatch/support both addr and int types
	value, err := syscall.GetsockoptInt(int(fd), level, opt)
	if err != nil {
		return Errno(err)
	}
	value32 := int32(value)
	size := int32(4)
	if err := valueOut.Pack(value32); err != nil {
		return UINT64_MAX // FIXME
	}
	if err := valueSizeOut.Pack(size); err != nil {
		return UINT64_MAX // FIXME
	}
	return 0
}

func (k *PosixKernel) Setsockopt(fd co.Fd, level, opt int, valueIn co.Buf, size int) uint64 {
	// TODO: dispatch/support all setsockopt types
	if size != 4 {
		fmt.Fprintf(os.Stderr, "WARNING: unsupported Setsockopt type %d\n", size)
		return UINT64_MAX // FIXME
	}
	var value int32
	if err := valueIn.Unpack(&value); err != nil {
		return UINT64_MAX // FIXME
	}
	if err := syscall.SetsockoptInt(int(fd), level, opt, opt); err != nil {
		return Errno(err)
	}
	return 0
}
<commit_msg>add a partial recvfrom<commit_after>package posix

import (
	"fmt"
	"os"
	"syscall"

	co "github.com/lunixbochs/usercorn/go/kernel/common"
)

func (k *PosixKernel) Socket(domain, typ, protocol int) uint64 {
	fd, err := syscall.Socket(domain, typ, protocol)
	if err != nil {
		return Errno(err)
	}
	return uint64(fd)
}

func (k *PosixKernel) Connect(fd co.Fd, sa syscall.Sockaddr, size co.Len) uint64 {
	return Errno(syscall.Connect(int(fd), sa))
}

func (k *PosixKernel) Bind(fd co.Fd, sa syscall.Sockaddr, size co.Len) uint64 {
	return Errno(syscall.Bind(int(fd), sa))
}

func (k *PosixKernel) Sendto(fd co.Fd, buf co.Buf, size co.Len, flags int, sa syscall.Sockaddr, socklen co.Len) uint64 {
	msg := make([]byte, size)
	if err := buf.Unpack(msg); err != nil {
		return UINT64_MAX // FIXME
	}
	return Errno(syscall.Sendto(int(fd), msg, flags, sa))
}

func (k *PosixKernel) Recvfrom(fd co.Fd, buf co.Buf, size co.Len, flags int, from co.Buf, fromlen co.Len) uint64 {
	p := make([]byte, size)
	if n, _, err := syscall.Recvfrom(int(fd), p, flags); err != nil {
		// TODO: need kernel.Pack() so we can pack a sockaddr into from
		buf.Pack(p)
		return uint64(n)
	} else {
		return UINT64_MAX // FIXME
	}
}

func (k *PosixKernel) Getsockopt(fd co.Fd, level, opt int, valueOut, valueSizeOut co.Buf) uint64 {
	// TODO: dispatch/support both addr and int types
	value, err := syscall.GetsockoptInt(int(fd), level, opt)
	if err != nil {
		return Errno(err)
	}
	value32 := int32(value)
	size := int32(4)
	if err := valueOut.Pack(value32); err != nil {
		return UINT64_MAX // FIXME
	}
	if err := valueSizeOut.Pack(size); err != nil {
		return UINT64_MAX // FIXME
	}
	return 0
}

func (k *PosixKernel) Setsockopt(fd co.Fd, level, opt int, valueIn co.Buf, size int) uint64 {
	// TODO: dispatch/support all setsockopt types
	if size != 4 {
		fmt.Fprintf(os.Stderr, "WARNING: unsupported Setsockopt type %d\n", size)
		return UINT64_MAX // FIXME
	}
	var value int32
	if err := valueIn.Unpack(&value); err != nil {
		return UINT64_MAX // FIXME
	}
	if err := syscall.SetsockoptInt(int(fd), level, opt, opt); err != nil {
		return Errno(err)
	}
	return 0
}
<|endoftext|>


<commit_before>package cron

import (
	"encoding/json"
	"io/ioutil"
	"time"

	log "github.com/Sirupsen/logrus"

	"github.com/parnurzeal/gorequest"
	"github.com/robfig/cron"
	"github.com/spf13/viper"
	"github.com/yroffin/jarvis-go-ext/server/types"
	"github.com/yroffin/jarvis-go-ext/server/utils/logger"
)

// handler : handler for connector register
func handler() {

	// define default value for this connector
	m := &types.Connector{
		Name:       "go-dio",
		Icon:       "settings_input_antenna",
		Adress:     "http://" + viper.GetString("jarvis.module.interface") + ":" + viper.GetString("jarvis.module.port"),
		IsRenderer: true,
		IsSensor:   false,
		CanAnswer:  false,
	}

	mJSON, _ := json.Marshal(m)

	request := gorequest.New().Timeout(2 * time.Second)
	resp, _, errs := request.
		Post(viper.GetString("jarvis.server.url") + "/api/connectors/*?task=register").
		Send(string(mJSON)).
		End()
	if errs != nil {
		logger.NewLogger().WithFields(log.Fields{
			"errors": errs,
		}).Info("CRON")
	}

	if b, err := ioutil.ReadAll(resp.Body); err == nil {
		logger.NewLogger().WithFields(log.Fields{
			"body":   string(b),
			"status": resp.Status,
		}).Info("CRON")
	}
}

// Init : init cron service
func Init(cr string) int {
	// first call
	handler()
	// init cron
	c := cron.New()
	c.AddFunc(cr, handler)
	c.Start()
	return 0
}
<commit_msg>Correction, continue quand le serveur est eteint<commit_after>package cron

import (
	"encoding/json"
	"io/ioutil"
	"time"

	log "github.com/Sirupsen/logrus"

	"github.com/parnurzeal/gorequest"
	"github.com/robfig/cron"
	"github.com/spf13/viper"
	"github.com/yroffin/jarvis-go-ext/server/types"
	"github.com/yroffin/jarvis-go-ext/server/utils/logger"
)

// handler : handler for connector register
func handler() {

	// define default value for this connector
	m := &types.Connector{
		Name:       "go-dio",
		Icon:       "settings_input_antenna",
		Adress:     "http://" + viper.GetString("jarvis.module.interface") + ":" + viper.GetString("jarvis.module.port"),
		IsRenderer: true,
		IsSensor:   false,
		CanAnswer:  false,
	}

	mJSON, _ := json.Marshal(m)

	request := gorequest.New().Timeout(2 * time.Second)
	resp, _, errs := request.
		Post(viper.GetString("jarvis.server.url") + "/api/connectors/*?task=register").
		Send(string(mJSON)).
		End()
	if errs != nil {
		logger.NewLogger().WithFields(log.Fields{
			"errors": errs,
		}).Info("CRON")
		return
	}

	if b, err := ioutil.ReadAll(resp.Body); err == nil {
		logger.NewLogger().WithFields(log.Fields{
			"body":   string(b),
			"status": resp.Status,
		}).Info("CRON")
	} else {
		logger.NewLogger().WithFields(log.Fields{
			"body":   string(b),
			"status": resp.Status,
		}).Info("WARN")
	}
}

// Init : init cron service
func Init(cr string) int {
	// first call
	handler()
	// init cron
	c := cron.New()
	c.AddFunc(cr, handler)
	c.Start()
	return 0
}
<|endoftext|>


<commit_before>package vppcalls

import (
	"bytes"
	"fmt"
	"regexp"
	"strconv"
	"strings"

	govppapi "git.fd.io/govpp.git/api"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/common/bin_api/vpe"
)

// VersionInfo contains values returned from ShowVersion
type VersionInfo struct {
	Program        string
	Version        string
	BuildDate      string
	BuildDirectory string
}

// GetVersionInfo retrieves version info
func GetVersionInfo(vppChan *govppapi.Channel) (*VersionInfo, error) {
	req := &vpe.ShowVersion{}
	reply := &vpe.ShowVersionReply{}

	if err := vppChan.SendRequest(req).ReceiveReply(reply); err != nil {
		return nil, err
	} else if reply.Retval != 0 {
		return nil, fmt.Errorf("%s returned %d", reply.GetMessageName(), reply.Retval)
	}

	info := &VersionInfo{
		Program:        string(cleanBytes(reply.Program)),
		Version:        string(cleanBytes(reply.Version)),
		BuildDate:      string(cleanBytes(reply.BuildDate)),
		BuildDirectory: string(cleanBytes(reply.BuildDirectory)),
	}

	return info, nil
}

// RunCliCommand executes CLI command and returns output
func RunCliCommand(vppChan *govppapi.Channel, cmd string) ([]byte, error) {
	req := &vpe.CliInband{
		Cmd:    []byte(cmd),
		Length: uint32(len(cmd)),
	}
	reply := &vpe.CliInbandReply{}

	if err := vppChan.SendRequest(req).ReceiveReply(reply); err != nil {
		return nil, err
	} else if reply.Retval != 0 {
		return nil, fmt.Errorf("%s returned %d", reply.GetMessageName(), reply.Retval)
	}

	return reply.Reply[:reply.Length], nil
}

// MemoryInfo contains values returned from 'show memory'
type MemoryInfo struct {
	Threads []MemoryThread `json:"threads"`
}

// MemoryThread represents single thread memory counters
type MemoryThread struct {
	ID        uint   `json:"id"`
	Name      string `json:"name"`
	Objects   uint64 `json:"objects"`
	Used      uint64 `json:"used"`
	Total     uint64 `json:"total"`
	Free      uint64 `json:"free"`
	Reclaimed uint64 `json:"reclaimed"`
	Overhead  uint64 `json:"overhead"`
	Capacity  uint64 `json:"capacity"`
}

// GetNodeCounters retrieves node counters info
func GetMemory(vppChan *govppapi.Channel) (*MemoryInfo, error) {
	data, err := RunCliCommand(vppChan, "show memory")
	if err != nil {
		return nil, err
	}

	var threads []MemoryThread
	var thread *MemoryThread

	for _, line := range strings.Split(string(data), "\n") {
		if thread != nil {
			for _, part := range strings.Split(line, ",") {
				fields := strings.Fields(strings.TrimSpace(part))
				if len(fields) > 1 {
					switch fields[1] {
					case "objects":
						thread.Objects = strToUint64(fields[0])
					case "of":
						thread.Used = strToUint64(fields[0])
						thread.Total = strToUint64(fields[2])
					case "free":
						thread.Free = strToUint64(fields[0])
					case "reclaimed":
						thread.Reclaimed = strToUint64(fields[0])
					case "overhead":
						thread.Overhead = strToUint64(fields[0])
					case "capacity":
						thread.Capacity = strToUint64(fields[0])
					}
				}
			}
			threads = append(threads, *thread)
			thread = nil
			continue
		}
		fields := strings.Fields(line)
		if len(fields) == 3 {
			if fields[0] == "Thread" {
				id, err := strconv.ParseUint(fields[1], 10, 64)
				if err != nil {
					return nil, err
				}
				thread = &MemoryThread{
					ID:   uint(id),
					Name: strings.SplitN(fields[2], string(0x00), 2)[0],
				}
				continue
			}
		}
	}

	info := &MemoryInfo{
		Threads: threads,
	}

	return info, nil
}

// NodeCounterInfo contains values returned from 'show node counters'
type NodeCounterInfo struct {
	Counters []NodeCounter `json:"counters"`
}

// NodeCounter represents single node counter
type NodeCounter struct {
	Count  uint64 `json:"count"`
	Node   string `json:"node"`
	Reason string `json:"reason"`
}

// GetNodeCounters retrieves node counters info
func GetNodeCounters(vppChan *govppapi.Channel) (*NodeCounterInfo, error) {
	data, err := RunCliCommand(vppChan, "show node counters")
	if err != nil {
		return nil, err
	}

	var counters []NodeCounter

	for _, line := range strings.Split(string(data), "\n") {
		fields := strings.Fields(line)
		if len(fields) == 3 {
			if fields[0] == "Count" {
				counters = []NodeCounter{}
				continue
			}
			if counters != nil {
				count, err := strconv.ParseUint(fields[0], 10, 64)
				if err != nil {
					return nil, err
				}
				counters = append(counters, NodeCounter{
					Count:  count,
					Node:   fields[1],
					Reason: fields[2],
				})
			}
		}
	}

	info := &NodeCounterInfo{
		Counters: counters,
	}

	return info, nil
}

// RuntimeInfo contains values returned from 'show runtime'
type RuntimeInfo struct {
	Items []RuntimeItem `json:"items"`
}

// RuntimeItem represents single runtime item
type RuntimeItem struct {
	Name        string  `json:"name"`
	State       string  `json:"state"`
	Calls       uint64  `json:"calls"`
	Vectors     uint64  `json:"vectors"`
	Suspends    uint64  `json:"suspends"`
	Clocks      float64 `json:"clocks"`
	VectorsCall float64 `json:"vectors_call"`
}

// GetNodeCounters retrieves node counters info
func GetRuntimeInfo(vppChan *govppapi.Channel) (*RuntimeInfo, error) {
	data, err := RunCliCommand(vppChan, "show runtime")
	if err != nil {
		return nil, err
	}

	var items []RuntimeItem

	for _, line := range strings.Split(string(data), "\n") {
		// TODO; use regexp instead of replacing
		line = strings.Replace(line, "event wait", "event-wait", -1)
		line = strings.Replace(line, "any wait", "any-wait", -1)

		fields := strings.Fields(line)
		if len(fields) == 7 {
			if fields[0] == "Name" {
				items = []RuntimeItem{}
				continue
			}
			if items != nil {
				calls, err := strconv.ParseUint(fields[2], 10, 64)
				if err != nil {
					return nil, err
				}
				vectors, err := strconv.ParseUint(fields[3], 10, 64)
				if err != nil {
					return nil, err
				}
				suspends, err := strconv.ParseUint(fields[4], 10, 64)
				if err != nil {
					return nil, err
				}
				clocks, err := strconv.ParseFloat(fields[5], 10)
				if err != nil {
					return nil, err
				}
				vectorsCall, err := strconv.ParseFloat(fields[6], 10)
				if err != nil {
					return nil, err
				}
				items = append(items, RuntimeItem{
					Name:        fields[0],
					State:       fields[1],
					Calls:       calls,
					Vectors:     vectors,
					Suspends:    suspends,
					Clocks:      clocks,
					VectorsCall: vectorsCall,
				})
			}
		}
	}

	info := &RuntimeInfo{
		Items: items,
	}

	return info, nil
}

// BuffersInfo contains values returned from 'show buffers'
type BuffersInfo struct {
	Items []BuffersItem `json:"items"`
}

// BuffersItem represents single buffers item
type BuffersItem struct {
	ThreadID uint   `json:"thread_id"`
	Name     string `json:"name"`
	Index    uint   `json:"index"`
	Size     uint64 `json:"size"`
	Alloc    uint64 `json:"alloc"`
	Free     uint64 `json:"free"`
	NumAlloc uint64 `json:"num_alloc"`
	NumFree  uint64 `json:"num_free"`
}

var buffersRe = regexp.MustCompile(`^\s+(\d+)\s+(\w+(?:[ \-]\w+)*)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+).*$`)

// GetBuffersInfo retrieves buffers info
func GetBuffersInfo(vppChan *govppapi.Channel) (*BuffersInfo, error) {
	data, err := RunCliCommand(vppChan, "show buffers")
	if err != nil {
		return nil, err
	}

	var items []BuffersItem

	for i, line := range strings.Split(string(data), "\n") {
		// Skip empty lines
		if strings.TrimSpace(line) == "" {
			continue
		}
		// Check first line
		if i == 0 {
			fields := strings.Fields(line)
			// Verify header
			if len(fields) != 8 || fields[0] != "Thread" {
				return nil, fmt.Errorf("invalid header for `show buffers` received: %q", line)
			}
			continue
		}

		// Parse lines using regexp
		matches := buffersRe.FindStringSubmatch(line)
		if len(matches)-1 != 8 {
			return nil, fmt.Errorf("parsing failed for `show buffers` line: %q", line)
		}
		fields := matches[1:]

		threadID, err := strconv.ParseUint(fields[0], 10, 64)
		if err != nil {
			return nil, err
		}
		index, err := strconv.ParseUint(fields[2], 10, 64)
		if err != nil {
			return nil, err
		}
		size, err := strconv.ParseUint(fields[3], 10, 64)
		if err != nil {
			return nil, err
		}
		alloc, err := strconv.ParseUint(fields[4], 10, 64)
		if err != nil {
			return nil, err
		}
		free, err := strconv.ParseUint(fields[5], 10, 64)
		if err != nil {
			return nil, err
		}
		numAlloc, err := strconv.ParseUint(fields[6], 10, 64)
		if err != nil {
			return nil, err
		}
		numFree, err := strconv.ParseUint(fields[7], 10, 64)
		if err != nil {
			return nil, err
		}
		items = append(items, BuffersItem{
			ThreadID: uint(threadID),
			Name:     fields[1],
			Index:    uint(index),
			Size:     size,
			Alloc:    alloc,
			Free:     free,
			NumAlloc: numAlloc,
			NumFree:  numFree,
		})
	}

	info := &BuffersInfo{
		Items: items,
	}

	return info, nil
}

func strToUint64(s string) uint64 {
	s = strings.Replace(s, "k", "000", 1)
	num, err := strconv.ParseUint(s, 10, 64)
	if err != nil {
		return 0
	}
	return num
}

func cleanBytes(b []byte) []byte {
	return bytes.SplitN(b, []byte{0x00}, 2)[0]
}
<commit_msg>Use regexp to parse memory info<commit_after>package vppcalls

import (
	"bytes"
	"fmt"
	"regexp"
	"strconv"
	"strings"

	govppapi "git.fd.io/govpp.git/api"
	"github.com/ligato/vpp-agent/plugins/defaultplugins/common/bin_api/vpe"
)

// VersionInfo contains values returned from ShowVersion
type VersionInfo struct {
	Program        string
	Version        string
	BuildDate      string
	BuildDirectory string
}

// GetVersionInfo retrieves version info
func GetVersionInfo(vppChan *govppapi.Channel) (*VersionInfo, error) {
	req := &vpe.ShowVersion{}
	reply := &vpe.ShowVersionReply{}

	if err := vppChan.SendRequest(req).ReceiveReply(reply); err != nil {
		return nil, err
	} else if reply.Retval != 0 {
		return nil, fmt.Errorf("%s returned %d", reply.GetMessageName(), reply.Retval)
	}

	info := &VersionInfo{
		Program:        string(cleanBytes(reply.Program)),
		Version:        string(cleanBytes(reply.Version)),
		BuildDate:      string(cleanBytes(reply.BuildDate)),
		BuildDirectory: string(cleanBytes(reply.BuildDirectory)),
	}

	return info, nil
}

// RunCliCommand executes CLI command and returns output
func RunCliCommand(vppChan *govppapi.Channel, cmd string) ([]byte, error) {
	req := &vpe.CliInband{
		Cmd:    []byte(cmd),
		Length: uint32(len(cmd)),
	}
	reply := &vpe.CliInbandReply{}

	if err := vppChan.SendRequest(req).ReceiveReply(reply); err != nil {
		return nil, err
	} else if reply.Retval != 0 {
		return nil, fmt.Errorf("%s returned %d", reply.GetMessageName(), reply.Retval)
	}

	return reply.Reply[:reply.Length], nil
}

// MemoryInfo contains values returned from 'show memory'
type MemoryInfo struct {
	Threads []MemoryThread `json:"threads"`
}

// MemoryThread represents single thread memory counters
type MemoryThread struct {
	ID        uint   `json:"id"`
	Name      string `json:"name"`
	Objects   uint64 `json:"objects"`
	Used      uint64 `json:"used"`
	Total     uint64 `json:"total"`
	Free      uint64 `json:"free"`
	Reclaimed uint64 `json:"reclaimed"`
	Overhead  uint64 `json:"overhead"`
	Capacity  uint64 `json:"capacity"`
}

var memoryRe = regexp.MustCompile(`Thread\s+(\d+)\s+(\w+).?\s+(\d+) objects, (\d+k?) of (\d+k?) used, (\d+k?) free, (\d+k?) reclaimed, (\d+k?) overhead, (\d+k?) capacity`)

// GetNodeCounters retrieves node counters info
func GetMemory(vppChan *govppapi.Channel) (*MemoryInfo, error) {
	data, err := RunCliCommand(vppChan, "show memory")
	if err != nil {
		return nil, err
	}

	var threads []MemoryThread

	threadMatches := memoryRe.FindAllStringSubmatch(string(data), -1)
	for _, matches := range threadMatches {
		fields := matches[1:]
		if len(fields) != 9 {
			return nil, fmt.Errorf("invalid memory data for thread: %q", matches[0])
		}
		id, err := strconv.ParseUint(fields[0], 10, 64)
		if err != nil {
			return nil, err
		}
		thread := &MemoryThread{
			ID:        uint(id),
			Name:      fields[1],
			Objects:   strToUint64(fields[2]),
			Used:      strToUint64(fields[3]),
			Total:     strToUint64(fields[4]),
			Free:      strToUint64(fields[5]),
			Reclaimed: strToUint64(fields[6]),
			Overhead:  strToUint64(fields[7]),
			Capacity:  strToUint64(fields[8]),
		}
		threads = append(threads, *thread)
	}

	info := &MemoryInfo{
		Threads: threads,
	}

	return info, nil
}

// NodeCounterInfo contains values returned from 'show node counters'
type NodeCounterInfo struct {
	Counters []NodeCounter `json:"counters"`
}

// NodeCounter represents single node counter
type NodeCounter struct {
	Count  uint64 `json:"count"`
	Node   string `json:"node"`
	Reason string `json:"reason"`
}

// GetNodeCounters retrieves node counters info
func GetNodeCounters(vppChan *govppapi.Channel) (*NodeCounterInfo, error) {
	data, err := RunCliCommand(vppChan, "show node counters")
	if err != nil {
		return nil, err
	}

	var counters []NodeCounter

	for _, line := range strings.Split(string(data), "\n") {
		fields := strings.Fields(line)
		if len(fields) == 3 {
			if fields[0] == "Count" {
				counters = []NodeCounter{}
				continue
			}
			if counters != nil {
				count, err := strconv.ParseUint(fields[0], 10, 64)
				if err != nil {
					return nil, err
				}
				counters = append(counters, NodeCounter{
					Count:  count,
					Node:   fields[1],
					Reason: fields[2],
				})
			}
		}
	}

	info := &NodeCounterInfo{
		Counters: counters,
	}

	return info, nil
}

// RuntimeInfo contains values returned from 'show runtime'
type RuntimeInfo struct {
	Items []RuntimeItem `json:"items"`
}

// RuntimeItem represents single runtime item
type RuntimeItem struct {
	Name        string  `json:"name"`
	State       string  `json:"state"`
	Calls       uint64  `json:"calls"`
	Vectors     uint64  `json:"vectors"`
	Suspends    uint64  `json:"suspends"`
	Clocks      float64 `json:"clocks"`
	VectorsCall float64 `json:"vectors_call"`
}

// GetNodeCounters retrieves node counters info
func GetRuntimeInfo(vppChan *govppapi.Channel) (*RuntimeInfo, error) {
	data, err := RunCliCommand(vppChan, "show runtime")
	if err != nil {
		return nil, err
	}

	var items []RuntimeItem

	for _, line := range strings.Split(string(data), "\n") {
		// TODO; use regexp instead of replacing
		line = strings.Replace(line, "event wait", "event-wait", -1)
		line = strings.Replace(line, "any wait", "any-wait", -1)

		fields := strings.Fields(line)
		if len(fields) == 7 {
			if fields[0] == "Name" {
				items = []RuntimeItem{}
				continue
			}
			if items != nil {
				calls, err := strconv.ParseUint(fields[2], 10, 64)
				if err != nil {
					return nil, err
				}
				vectors, err := strconv.ParseUint(fields[3], 10, 64)
				if err != nil {
					return nil, err
				}
				suspends, err := strconv.ParseUint(fields[4], 10, 64)
				if err != nil {
					return nil, err
				}
				clocks, err := strconv.ParseFloat(fields[5], 10)
				if err != nil {
					return nil, err
				}
				vectorsCall, err := strconv.ParseFloat(fields[6], 10)
				if err != nil {
					return nil, err
				}
				items = append(items, RuntimeItem{
					Name:        fields[0],
					State:       fields[1],
					Calls:       calls,
					Vectors:     vectors,
					Suspends:    suspends,
					Clocks:      clocks,
					VectorsCall: vectorsCall,
				})
			}
		}
	}

	info := &RuntimeInfo{
		Items: items,
	}

	return info, nil
}

// BuffersInfo contains values returned from 'show buffers'
type BuffersInfo struct {
	Items []BuffersItem `json:"items"`
}

// BuffersItem represents single buffers item
type BuffersItem struct {
	ThreadID uint   `json:"thread_id"`
	Name     string `json:"name"`
	Index    uint   `json:"index"`
	Size     uint64 `json:"size"`
	Alloc    uint64 `json:"alloc"`
	Free     uint64 `json:"free"`
	NumAlloc uint64 `json:"num_alloc"`
	NumFree  uint64 `json:"num_free"`
}

var buffersRe = regexp.MustCompile(`^\s+(\d+)\s+(\w+(?:[ \-]\w+)*)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+).*$`)

// GetBuffersInfo retrieves buffers info
func GetBuffersInfo(vppChan *govppapi.Channel) (*BuffersInfo, error) {
	data, err := RunCliCommand(vppChan, "show buffers")
	if err != nil {
		return nil, err
	}

	var items []BuffersItem

	for i, line := range strings.Split(string(data), "\n") {
		// Skip empty lines
		if strings.TrimSpace(line) == "" {
			continue
		}
		// Check first line
		if i == 0 {
			fields := strings.Fields(line)
			// Verify header
			if len(fields) != 8 || fields[0] != "Thread" {
				return nil, fmt.Errorf("invalid header for `show buffers` received: %q", line)
			}
			continue
		}

		// Parse lines using regexp
		matches := buffersRe.FindStringSubmatch(line)
		if len(matches)-1 != 8 {
			return nil, fmt.Errorf("parsing failed for `show buffers` line: %q", line)
		}
		fields := matches[1:]

		threadID, err := strconv.ParseUint(fields[0], 10, 64)
		if err != nil {
			return nil, err
		}
		index, err := strconv.ParseUint(fields[2], 10, 64)
		if err != nil {
			return nil, err
		}
		size, err := strconv.ParseUint(fields[3], 10, 64)
		if err != nil {
			return nil, err
		}
		alloc, err := strconv.ParseUint(fields[4], 10, 64)
		if err != nil {
			return nil, err
		}
		free, err := strconv.ParseUint(fields[5], 10, 64)
		if err != nil {
			return nil, err
		}
		numAlloc, err := strconv.ParseUint(fields[6], 10, 64)
		if err != nil {
			return nil, err
		}
		numFree, err := strconv.ParseUint(fields[7], 10, 64)
		if err != nil {
			return nil, err
		}
		items = append(items, BuffersItem{
			ThreadID: uint(threadID),
			Name:     fields[1],
			Index:    uint(index),
			Size:     size,
			Alloc:    alloc,
			Free:     free,
			NumAlloc: numAlloc,
			NumFree:  numFree,
		})
	}

	info := &BuffersInfo{
		Items: items,
	}

	return info, nil
}

func strToUint64(s string) uint64 {
	s = strings.Replace(s, "k", "000", 1)
	num, err := strconv.ParseUint(s, 10, 64)
	if err != nil {
		return 0
	}
	return num
}

func cleanBytes(b []byte) []byte {
	return bytes.SplitN(b, []byte{0x00}, 2)[0]
}
<|endoftext|>


<commit_before>// Copyright 2015 Herman Tai
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// webserver demos how to start a simple HTTP server.
package main

import (
	"fmt"
	"log"
	"net/http"
)

type MyHandler struct{}

func (MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "User agent is: %s\n", r.UserAgent())
	fmt.Fprintf(w, "Referer is: %s\n", r.Referer())
}

func main() {
	var h MyHandler

	http.Handle("/", h)

	fmt.Println("Server is starting at localhost:4000")
	err := http.ListenAndServe("localhost:4000", nil)

	if err != nil {
		log.Fatal(err)
	}
}
<commit_msg>[go][webserver] Add a sample of using handler function<commit_after>// Copyright 2015 Herman Tai
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// webserver demos how to start a simple HTTP server.
package main

import (
	"fmt"
	"log"
	"net/http"
)

type MyHandler struct{}

func (MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "User agent is: %s\n", r.UserAgent())
	fmt.Fprintf(w, "Referer is: %s\n", r.Referer())
}

func myHandlerFunc(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "In myHandlerFunc:\n")
	fmt.Fprintf(w, "User agent is: %s\n", r.UserAgent())
	fmt.Fprintf(w, "Referer is: %s\n", r.Referer())
}

func main() {
	var h MyHandler

	http.Handle("/", h)
	http.HandleFunc("/func", myHandlerFunc)

	fmt.Println("Server is starting at localhost:8000")
	err := http.ListenAndServe("localhost:8000", nil)

	if err != nil {
		log.Fatal(err)
	}
}
<|endoftext|>