<commit_before>package core

import (
	"context"
	"crypto/x509"
	"net"
	"net/http"
	"time"

	jose "gopkg.in/square/go-jose.v2"

	caPB "github.com/letsencrypt/boulder/ca/proto"
	corepb "github.com/letsencrypt/boulder/core/proto"
	"github.com/letsencrypt/boulder/identifier"
	pubpb "github.com/letsencrypt/boulder/publisher/proto"
	rapb "github.com/letsencrypt/boulder/ra/proto"
	"github.com/letsencrypt/boulder/revocation"
	sapb "github.com/letsencrypt/boulder/sa/proto"
)

// A WebFrontEnd object supplies methods that can be hooked into
// the Go http module's server functions, principally http.HandleFunc()
//
// It also provides methods to configure the base for authorization and
// certificate URLs.
//
// It is assumed that the ACME server is laid out as follows:
// * One URL for new-authorization -> NewAuthz
// * One URL for new-certificate -> NewCert
// * One path for authorizations -> Authz
// * One path for certificates -> Cert
type WebFrontEnd interface {
	// Set the base URL for authorizations
	SetAuthzBase(ctx context.Context, path string)

	// Set the base URL for certificates
	SetCertBase(ctx context.Context, path string)

	// This method represents the ACME new-registration resource
	NewRegistration(ctx context.Context, response http.ResponseWriter, request *http.Request)

	// This method represents the ACME new-authorization resource
	NewAuthz(ctx context.Context, response http.ResponseWriter, request *http.Request)

	// This method represents the ACME new-certificate resource
	NewCert(ctx context.Context, response http.ResponseWriter, request *http.Request)

	// Provide access to requests for registration resources
	Registration(ctx context.Context, response http.ResponseWriter, request *http.Request)

	// Provide access to requests for authorization resources
	Authz(ctx context.Context, response http.ResponseWriter, request *http.Request)

	// Provide access to requests for authorization resources
	Cert(ctx context.Context, response http.ResponseWriter, request *http.Request)
}

// RegistrationAuthority defines the public interface for the Boulder RA
type RegistrationAuthority interface {
	// [WebFrontEnd]
	NewRegistration(ctx context.Context, reg Registration) (Registration, error)

	// [WebFrontEnd]
	NewAuthorization(ctx context.Context, authz Authorization, regID int64) (Authorization, error)

	// [WebFrontEnd]
	NewCertificate(ctx context.Context, csr CertificateRequest, regID int64) (Certificate, error)

	// [WebFrontEnd]
	UpdateRegistration(ctx context.Context, base, updates Registration) (Registration, error)

	// [WebFrontEnd]
	PerformValidation(ctx context.Context, req *rapb.PerformValidationRequest) (*corepb.Authorization, error)

	// [WebFrontEnd]
	RevokeCertificateWithReg(ctx context.Context, cert x509.Certificate, code revocation.Reason, regID int64) error

	// [WebFrontEnd]
	DeactivateRegistration(ctx context.Context, reg Registration) error

	// [WebFrontEnd]
	DeactivateAuthorization(ctx context.Context, auth Authorization) error

	// [WebFrontEnd]
	NewOrder(ctx context.Context, req *rapb.NewOrderRequest) (*corepb.Order, error)

	// [WebFrontEnd]
	FinalizeOrder(ctx context.Context, req *rapb.FinalizeOrderRequest) (*corepb.Order, error)

	// [AdminRevoker]
	AdministrativelyRevokeCertificate(ctx context.Context, cert x509.Certificate, code revocation.Reason, adminName string) error
}

// CertificateAuthority defines the public interface for the Boulder CA
type CertificateAuthority interface {
	// [RegistrationAuthority]
	IssuePrecertificate(ctx context.Context, issueReq *caPB.IssueCertificateRequest) (*caPB.IssuePrecertificateResponse, error)

	// [RegistrationAuthority]
	IssueCertificateForPrecertificate(ctx context.Context, req *caPB.IssueCertificateForPrecertificateRequest) (Certificate, error)

	GenerateOCSP(ctx context.Context, ocspReq *caPB.GenerateOCSPRequest) (*caPB.OCSPResponse, error)
}

// PolicyAuthority defines the public interface for the Boulder PA
type PolicyAuthority interface {
	WillingToIssue(domain identifier.ACMEIdentifier) error
	WillingToIssueWildcards(identifiers []identifier.ACMEIdentifier) error
	ChallengesFor(domain identifier.ACMEIdentifier) ([]Challenge, error)
	ChallengeTypeEnabled(t string) bool
	ValidDomain(domain string) error
}

// StorageGetter are the Boulder SA's read-only methods
type StorageGetter interface {
	GetRegistration(ctx context.Context, regID int64) (Registration, error)
	GetRegistrationByKey(ctx context.Context, jwk *jose.JSONWebKey) (Registration, error)
	GetCertificate(ctx context.Context, serial string) (Certificate, error)
	GetPrecertificate(ctx context.Context, req *sapb.Serial) (*corepb.Certificate, error)
	GetCertificateStatus(ctx context.Context, serial string) (CertificateStatus, error)
	CountCertificatesByNames(ctx context.Context, domains []string, earliest, latest time.Time) (countByDomain []*sapb.CountByNames_MapElement, err error)
	CountRegistrationsByIP(ctx context.Context, ip net.IP, earliest, latest time.Time) (int, error)
	CountRegistrationsByIPRange(ctx context.Context, ip net.IP, earliest, latest time.Time) (int, error)
	CountOrders(ctx context.Context, acctID int64, earliest, latest time.Time) (int, error)
	CountFQDNSets(ctx context.Context, window time.Duration, domains []string) (count int64, err error)
	FQDNSetExists(ctx context.Context, domains []string) (exists bool, err error)
	PreviousCertificateExists(ctx context.Context, req *sapb.PreviousCertificateExistsRequest) (exists *sapb.Exists, err error)
	GetOrder(ctx context.Context, req *sapb.OrderRequest) (*corepb.Order, error)
	GetOrderForNames(ctx context.Context, req *sapb.GetOrderForNamesRequest) (*corepb.Order, error)
	// New authz2 methods
	GetAuthorization2(ctx context.Context, req *sapb.AuthorizationID2) (*corepb.Authorization, error)
	GetAuthorizations2(ctx context.Context, req *sapb.GetAuthorizationsRequest) (*sapb.Authorizations, error)
	GetPendingAuthorization2(ctx context.Context, req *sapb.GetPendingAuthorizationRequest) (*corepb.Authorization, error)
	CountPendingAuthorizations2(ctx context.Context, req *sapb.RegistrationID) (*sapb.Count, error)
	GetValidOrderAuthorizations2(ctx context.Context, req *sapb.GetValidOrderAuthorizationsRequest) (*sapb.Authorizations, error)
	CountInvalidAuthorizations2(ctx context.Context, req *sapb.CountInvalidAuthorizationsRequest) (*sapb.Count, error)
	GetValidAuthorizations2(ctx context.Context, req *sapb.GetValidAuthorizationsRequest) (*sapb.Authorizations, error)
	SerialExists(ctx context.Context, req *sapb.Serial) (*sapb.Exists, error)
	KeyBlocked(ctx context.Context, req *sapb.KeyBlockedRequest) (*sapb.Exists, error)
}

// StorageAdder are the Boulder SA's write/update methods
type StorageAdder interface {
	NewRegistration(ctx context.Context, reg Registration) (created Registration, err error)
	UpdateRegistration(ctx context.Context, reg Registration) error
	AddCertificate(ctx context.Context, der []byte, regID int64, ocsp []byte, issued *time.Time) (digest string, err error)
	AddPrecertificate(ctx context.Context, req *sapb.AddCertificateRequest) (*corepb.Empty, error)
	AddSerial(ctx context.Context, req *sapb.AddSerialRequest) (*corepb.Empty, error)
	DeactivateRegistration(ctx context.Context, id int64) error
	NewOrder(ctx context.Context, order *corepb.Order) (*corepb.Order, error)
	SetOrderProcessing(ctx context.Context, order *corepb.Order) error
	FinalizeOrder(ctx context.Context, order *corepb.Order) error
	SetOrderError(ctx context.Context, order *corepb.Order) error
	RevokeCertificate(ctx context.Context, req *sapb.RevokeCertificateRequest) error
	// New authz2 methods
	NewAuthorizations2(ctx context.Context, req *sapb.AddPendingAuthorizationsRequest) (*sapb.Authorization2IDs, error)
	FinalizeAuthorization2(ctx context.Context, req *sapb.FinalizeAuthorizationRequest) error
	DeactivateAuthorization2(ctx context.Context, req *sapb.AuthorizationID2) (*corepb.Empty, error)
	AddBlockedKey(ctx context.Context, req *sapb.AddBlockedKeyRequest) (*corepb.Empty, error)
}

// StorageAuthority interface represents a simple key/value
// store.  It is divided into StorageGetter and StorageUpdater
// interfaces for privilege separation.
type StorageAuthority interface {
	StorageGetter
	StorageAdder
}

// Publisher defines the public interface for the Boulder Publisher
type Publisher interface {
	SubmitToSingleCTWithResult(ctx context.Context, req *pubpb.Request) (*pubpb.Result, error)
}
<commit_msg>Update StorageAuthority interface comment (#4825)<commit_after>package core

import (
	"context"
	"crypto/x509"
	"net"
	"net/http"
	"time"

	jose "gopkg.in/square/go-jose.v2"

	caPB "github.com/letsencrypt/boulder/ca/proto"
	corepb "github.com/letsencrypt/boulder/core/proto"
	"github.com/letsencrypt/boulder/identifier"
	pubpb "github.com/letsencrypt/boulder/publisher/proto"
	rapb "github.com/letsencrypt/boulder/ra/proto"
	"github.com/letsencrypt/boulder/revocation"
	sapb "github.com/letsencrypt/boulder/sa/proto"
)

// A WebFrontEnd object supplies methods that can be hooked into
// the Go http module's server functions, principally http.HandleFunc()
//
// It also provides methods to configure the base for authorization and
// certificate URLs.
//
// It is assumed that the ACME server is laid out as follows:
// * One URL for new-authorization -> NewAuthz
// * One URL for new-certificate -> NewCert
// * One path for authorizations -> Authz
// * One path for certificates -> Cert
type WebFrontEnd interface {
	// Set the base URL for authorizations
	SetAuthzBase(ctx context.Context, path string)

	// Set the base URL for certificates
	SetCertBase(ctx context.Context, path string)

	// This method represents the ACME new-registration resource
	NewRegistration(ctx context.Context, response http.ResponseWriter, request *http.Request)

	// This method represents the ACME new-authorization resource
	NewAuthz(ctx context.Context, response http.ResponseWriter, request *http.Request)

	// This method represents the ACME new-certificate resource
	NewCert(ctx context.Context, response http.ResponseWriter, request *http.Request)

	// Provide access to requests for registration resources
	Registration(ctx context.Context, response http.ResponseWriter, request *http.Request)

	// Provide access to requests for authorization resources
	Authz(ctx context.Context, response http.ResponseWriter, request *http.Request)

	// Provide access to requests for authorization resources
	Cert(ctx context.Context, response http.ResponseWriter, request *http.Request)
}

// RegistrationAuthority defines the public interface for the Boulder RA
type RegistrationAuthority interface {
	// [WebFrontEnd]
	NewRegistration(ctx context.Context, reg Registration) (Registration, error)

	// [WebFrontEnd]
	NewAuthorization(ctx context.Context, authz Authorization, regID int64) (Authorization, error)

	// [WebFrontEnd]
	NewCertificate(ctx context.Context, csr CertificateRequest, regID int64) (Certificate, error)

	// [WebFrontEnd]
	UpdateRegistration(ctx context.Context, base, updates Registration) (Registration, error)

	// [WebFrontEnd]
	PerformValidation(ctx context.Context, req *rapb.PerformValidationRequest) (*corepb.Authorization, error)

	// [WebFrontEnd]
	RevokeCertificateWithReg(ctx context.Context, cert x509.Certificate, code revocation.Reason, regID int64) error

	// [WebFrontEnd]
	DeactivateRegistration(ctx context.Context, reg Registration) error

	// [WebFrontEnd]
	DeactivateAuthorization(ctx context.Context, auth Authorization) error

	// [WebFrontEnd]
	NewOrder(ctx context.Context, req *rapb.NewOrderRequest) (*corepb.Order, error)

	// [WebFrontEnd]
	FinalizeOrder(ctx context.Context, req *rapb.FinalizeOrderRequest) (*corepb.Order, error)

	// [AdminRevoker]
	AdministrativelyRevokeCertificate(ctx context.Context, cert x509.Certificate, code revocation.Reason, adminName string) error
}

// CertificateAuthority defines the public interface for the Boulder CA
type CertificateAuthority interface {
	// [RegistrationAuthority]
	IssuePrecertificate(ctx context.Context, issueReq *caPB.IssueCertificateRequest) (*caPB.IssuePrecertificateResponse, error)

	// [RegistrationAuthority]
	IssueCertificateForPrecertificate(ctx context.Context, req *caPB.IssueCertificateForPrecertificateRequest) (Certificate, error)

	GenerateOCSP(ctx context.Context, ocspReq *caPB.GenerateOCSPRequest) (*caPB.OCSPResponse, error)
}

// PolicyAuthority defines the public interface for the Boulder PA
type PolicyAuthority interface {
	WillingToIssue(domain identifier.ACMEIdentifier) error
	WillingToIssueWildcards(identifiers []identifier.ACMEIdentifier) error
	ChallengesFor(domain identifier.ACMEIdentifier) ([]Challenge, error)
	ChallengeTypeEnabled(t string) bool
	ValidDomain(domain string) error
}

// StorageGetter are the Boulder SA's read-only methods
type StorageGetter interface {
	GetRegistration(ctx context.Context, regID int64) (Registration, error)
	GetRegistrationByKey(ctx context.Context, jwk *jose.JSONWebKey) (Registration, error)
	GetCertificate(ctx context.Context, serial string) (Certificate, error)
	GetPrecertificate(ctx context.Context, req *sapb.Serial) (*corepb.Certificate, error)
	GetCertificateStatus(ctx context.Context, serial string) (CertificateStatus, error)
	CountCertificatesByNames(ctx context.Context, domains []string, earliest, latest time.Time) (countByDomain []*sapb.CountByNames_MapElement, err error)
	CountRegistrationsByIP(ctx context.Context, ip net.IP, earliest, latest time.Time) (int, error)
	CountRegistrationsByIPRange(ctx context.Context, ip net.IP, earliest, latest time.Time) (int, error)
	CountOrders(ctx context.Context, acctID int64, earliest, latest time.Time) (int, error)
	CountFQDNSets(ctx context.Context, window time.Duration, domains []string) (count int64, err error)
	FQDNSetExists(ctx context.Context, domains []string) (exists bool, err error)
	PreviousCertificateExists(ctx context.Context, req *sapb.PreviousCertificateExistsRequest) (exists *sapb.Exists, err error)
	GetOrder(ctx context.Context, req *sapb.OrderRequest) (*corepb.Order, error)
	GetOrderForNames(ctx context.Context, req *sapb.GetOrderForNamesRequest) (*corepb.Order, error)
	// New authz2 methods
	GetAuthorization2(ctx context.Context, req *sapb.AuthorizationID2) (*corepb.Authorization, error)
	GetAuthorizations2(ctx context.Context, req *sapb.GetAuthorizationsRequest) (*sapb.Authorizations, error)
	GetPendingAuthorization2(ctx context.Context, req *sapb.GetPendingAuthorizationRequest) (*corepb.Authorization, error)
	CountPendingAuthorizations2(ctx context.Context, req *sapb.RegistrationID) (*sapb.Count, error)
	GetValidOrderAuthorizations2(ctx context.Context, req *sapb.GetValidOrderAuthorizationsRequest) (*sapb.Authorizations, error)
	CountInvalidAuthorizations2(ctx context.Context, req *sapb.CountInvalidAuthorizationsRequest) (*sapb.Count, error)
	GetValidAuthorizations2(ctx context.Context, req *sapb.GetValidAuthorizationsRequest) (*sapb.Authorizations, error)
	SerialExists(ctx context.Context, req *sapb.Serial) (*sapb.Exists, error)
	KeyBlocked(ctx context.Context, req *sapb.KeyBlockedRequest) (*sapb.Exists, error)
}

// StorageAdder are the Boulder SA's write/update methods
type StorageAdder interface {
	NewRegistration(ctx context.Context, reg Registration) (created Registration, err error)
	UpdateRegistration(ctx context.Context, reg Registration) error
	AddCertificate(ctx context.Context, der []byte, regID int64, ocsp []byte, issued *time.Time) (digest string, err error)
	AddPrecertificate(ctx context.Context, req *sapb.AddCertificateRequest) (*corepb.Empty, error)
	AddSerial(ctx context.Context, req *sapb.AddSerialRequest) (*corepb.Empty, error)
	DeactivateRegistration(ctx context.Context, id int64) error
	NewOrder(ctx context.Context, order *corepb.Order) (*corepb.Order, error)
	SetOrderProcessing(ctx context.Context, order *corepb.Order) error
	FinalizeOrder(ctx context.Context, order *corepb.Order) error
	SetOrderError(ctx context.Context, order *corepb.Order) error
	RevokeCertificate(ctx context.Context, req *sapb.RevokeCertificateRequest) error
	// New authz2 methods
	NewAuthorizations2(ctx context.Context, req *sapb.AddPendingAuthorizationsRequest) (*sapb.Authorization2IDs, error)
	FinalizeAuthorization2(ctx context.Context, req *sapb.FinalizeAuthorizationRequest) error
	DeactivateAuthorization2(ctx context.Context, req *sapb.AuthorizationID2) (*corepb.Empty, error)
	AddBlockedKey(ctx context.Context, req *sapb.AddBlockedKeyRequest) (*corepb.Empty, error)
}

// StorageAuthority interface represents a simple key/value
// store. The add and get interfaces contained within are divided
// for privilege separation.
type StorageAuthority interface {
	StorageGetter
	StorageAdder
}

// Publisher defines the public interface for the Boulder Publisher
type Publisher interface {
	SubmitToSingleCTWithResult(ctx context.Context, req *pubpb.Request) (*pubpb.Result, error)
}
<|endoftext|>


<commit_before>// Adapted from https://raw.githubusercontent.com/gorilla/websocket/master/examples/chat/conn.go

package main

import (
	"encoding/json"
	"log"
	"net/http"
	"time"

	"github.com/gorilla/websocket"
)

const (
	// Time allowed to write a message to the peer.
	writeWait = 10 * time.Second

	// Time allowed to read the next pong message from the peer.
	pongWait = 60 * time.Second

	// Send pings to peer with this period. Must be less than pongWait.
	pingPeriod = (pongWait * 9) / 10

	// Maximum message size allowed from peer.
	maxMessageSize = 512
)

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
}

// connection is an middleman between the websocket connection and the hub.
type Connection struct {
	// The websocket connection.
	ws *websocket.Conn

	// Buffered channels of inbound and outbound messages.
	receive chan *Message
	send    chan *Message
}

// readPump pumps messages from the websocket connection to the hub.
func (c *Connection) readPump() {
	defer func() {
		c.ws.Close()
		close(c.receive)
	}()
	c.ws.SetReadLimit(maxMessageSize)
	c.ws.SetReadDeadline(time.Now().Add(pongWait))
	c.ws.SetPongHandler(func(string) error { c.ws.SetReadDeadline(time.Now().Add(pongWait)); return nil })
	for {
		// read raw message off the socket
		_, raw, err := c.ws.ReadMessage()
		if err != nil {
			log.Println("Error reading message off socket", err)
			break
		}

		// uncompress LZW
		uncompressed := LzwDecompress(string(raw))

		// unmarshal JSON
		var message Message
		err = json.Unmarshal(uncompressed, &message)
		if err != nil {
			log.Println("Error unmarshalling JSON", err)
			continue
		}

		// process the message
		if message.Type == "h" {
			// respond to heartbeat right away, but still send it to the client as well
			c.send <- &Message{Type: "h", Time: MakeTimestamp()}
		}

		c.receive <- &message
	}
}

// write a message with the given message type and payload.
func (c *Connection) write(mt int, payload []byte) error {
	c.ws.SetWriteDeadline(time.Now().Add(writeWait))
	return c.ws.WriteMessage(mt, payload)
}

// write a JSON message.
func (c *Connection) writeMessage(message *Message) error {
	c.ws.SetWriteDeadline(time.Now().Add(writeWait))

	// marshal to JSON
	str, err := json.Marshal(message)
	if err != nil {
		log.Println("Error marshalling message to JSON", err)
		return nil
	}

	// compress with LZW
	compressed := LzwCompress(str)

	// send
	return c.ws.WriteMessage(websocket.TextMessage, []byte(compressed))
}

// writePump pumps messages from the hub to the websocket connection.
func (c *Connection) writePump() {
	ticker := time.NewTicker(pingPeriod)
	defer func() {
		ticker.Stop()
		c.ws.Close()
	}()
	for {
		select {
		case message, ok := <-c.send:
			if !ok {
				c.write(websocket.CloseMessage, []byte{})
				return
			}

			if err := c.writeMessage(message); err != nil {
				log.Println("Error sending message:", err)
				return
			}
		case <-ticker.C:
			if err := c.write(websocket.PingMessage, []byte{}); err != nil {
				log.Println("Error sending ping:", err)
				return
			}
		}
	}
}

// serverWs handles websocket requests from the peer.
func serveWs(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		http.Error(w, "Method not allowed", 405)
		return
	}
	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		return
	}
	c := &Connection{ws, make(chan *Message, 256), make(chan *Message, 256)}
	makeClient(c)
	go c.writePump()
	c.readPump()
}
<commit_msg>slightly less error messages<commit_after>// Adapted from https://raw.githubusercontent.com/gorilla/websocket/master/examples/chat/conn.go

package main

import (
	"encoding/json"
	"io"
	"log"
	"net/http"
	"time"

	"github.com/gorilla/websocket"
)

const (
	// Time allowed to write a message to the peer.
	writeWait = 10 * time.Second

	// Time allowed to read the next pong message from the peer.
	pongWait = 60 * time.Second

	// Send pings to peer with this period. Must be less than pongWait.
	pingPeriod = (pongWait * 9) / 10

	// Maximum message size allowed from peer.
	maxMessageSize = 512
)

var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
}

// connection is an middleman between the websocket connection and the hub.
type Connection struct {
	// The websocket connection.
	ws *websocket.Conn

	// Buffered channels of inbound and outbound messages.
	receive chan *Message
	send    chan *Message
}

// readPump pumps messages from the websocket connection to the hub.
func (c *Connection) readPump() {
	defer func() {
		c.ws.Close()
		close(c.receive)
	}()
	c.ws.SetReadLimit(maxMessageSize)
	c.ws.SetReadDeadline(time.Now().Add(pongWait))
	c.ws.SetPongHandler(func(string) error { c.ws.SetReadDeadline(time.Now().Add(pongWait)); return nil })
	for {
		// read raw message off the socket
		_, raw, err := c.ws.ReadMessage()
		if err != nil {
			if err != io.EOF {
				log.Println("Error reading message off socket", err)
			}
			break
		}

		// uncompress LZW
		uncompressed := LzwDecompress(string(raw))

		// unmarshal JSON
		var message Message
		err = json.Unmarshal(uncompressed, &message)
		if err != nil {
			log.Println("Error unmarshalling JSON", err)
			continue
		}

		// process the message
		if message.Type == "h" {
			// respond to heartbeat right away, but still send it to the client as well
			c.send <- &Message{Type: "h", Time: MakeTimestamp()}
		}

		c.receive <- &message
	}
}

// write a message with the given message type and payload.
func (c *Connection) write(mt int, payload []byte) error {
	c.ws.SetWriteDeadline(time.Now().Add(writeWait))
	return c.ws.WriteMessage(mt, payload)
}

// write a JSON message.
func (c *Connection) writeMessage(message *Message) error {
	c.ws.SetWriteDeadline(time.Now().Add(writeWait))

	// marshal to JSON
	str, err := json.Marshal(message)
	if err != nil {
		log.Println("Error marshalling message to JSON", err)
		return nil
	}

	// compress with LZW
	compressed := LzwCompress(str)

	// send
	return c.ws.WriteMessage(websocket.TextMessage, []byte(compressed))
}

// writePump pumps messages from the hub to the websocket connection.
func (c *Connection) writePump() {
	ticker := time.NewTicker(pingPeriod)
	defer func() {
		ticker.Stop()
		c.ws.Close()
	}()
	for {
		select {
		case message, ok := <-c.send:
			if !ok {
				c.write(websocket.CloseMessage, []byte{})
				return
			}

			if err := c.writeMessage(message); err != nil {
				log.Println("Error sending message:", err)
				return
			}
		case <-ticker.C:
			if err := c.write(websocket.PingMessage, []byte{}); err != nil {
				log.Println("Error sending ping:", err)
				return
			}
		}
	}
}

// serverWs handles websocket requests from the peer.
func serveWs(w http.ResponseWriter, r *http.Request) {
	if r.Method != "GET" {
		http.Error(w, "Method not allowed", 405)
		return
	}
	ws, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
		return
	}
	c := &Connection{ws, make(chan *Message, 256), make(chan *Message, 256)}
	makeClient(c)
	go c.writePump()
	c.readPump()
}
<|endoftext|>


<commit_before>// Example get-active-window reads the _NET_ACTIVE_WINDOW property of the root
// window and uses the result (a window id) to get the name of the window.
package main

import (
	"math/rand"
	"time"
	"database/sql"
	"fmt"
	"github.com/erasche/gologme"
	_ "github.com/mattn/go-sqlite3"
	"log"
	"net"
	"net/http"
	"net/rpc"
)

type Golog struct {
	Db *sql.DB
}

func (t *Golog) logToDb(uid int, windowlogs []gologme.WindowLogs, keylogs []gologme.KeyLogs, wll int){
	tx, err := t.Db.Begin()
	if err != nil {
		log.Fatal(err)
	}
	stmt, err := tx.Prepare("insert into windowLogs (time, name) values (?, ?)")
	if err != nil {
		log.Fatal(err)
	}
	defer stmt.Close()

	log.Printf("%d logs from [%d]\n", wll, uid)
	for i, w := range windowlogs {
		_, err = stmt.Exec(w.Time.Unix(), w.Name)
		if err != nil {
			log.Fatal(err)
		}
		if i >= wll - 1 {
			break
		}
	}

	tx.Commit()
}

func (t *Golog) ensureAuth(user string, key string) (int, error) {
	// Pretty assuredly not safe from timing attacks.
	stmt, err := t.Db.Prepare("select id from users where username = ? and api_key = ?")
	if err != nil {
		return -1, err
	}
	defer stmt.Close()

	// Maybe helps against timing attacks? Hmm.
	time.Sleep(time.Duration(rand.Int31n(1000)) * time.Millisecond)

	var uid int
	err = stmt.QueryRow(user, key).Scan(&uid)
	if err != nil {
		return -1, err
	}

	return uid, nil
}

func (t *Golog) Log(args gologme.RpcArgs, result *gologme.Result) error {
	uid, err := t.ensureAuth(args.User, args.ApiKey)
	if err != nil {
		log.Fatal(err)
		*result = 1
		return nil
	} else {
		log.Printf("%s authenticated successfully as uid %d\n", args.User, uid)
	}

	t.logToDb(
		uid,
		args.Windows,
		args.KeyLogs,
		args.WindowLogsLength,
	)

	*result = 0
	return nil
}

func (t *Golog) setupDb(db *sql.DB) {
	dbCreation := `
	create table if not exists users (
		id integer not null primary key autoincrement,
		username text,
		api_key text
	);

	create table if not exists windowLogs (
		id integer not null primary key autoincrement,
		time integer,
		name text,
		foreign key (id) references users(id)
	)
	`

	_, err := db.Exec(dbCreation)
	if err != nil {
		log.Fatal(err)
	}
	t.Db = db
}

func main() {
	db, err := sql.Open("sqlite3", "file.db")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	golog := new(Golog)
	golog.setupDb(db)

	rpc.Register(golog)
	rpc.HandleHTTP()
	l, err := net.Listen("tcp", ":8080")
	if err != nil {
		log.Fatal("listen error:", err)
	}
	fmt.Println("Listening...")

	err = http.Serve(l, nil)
	if err != nil {
		log.Fatal("Error serving:", err)
	}
}
<commit_msg>Correct sql model<commit_after>// Example get-active-window reads the _NET_ACTIVE_WINDOW property of the root
// window and uses the result (a window id) to get the name of the window.
package main

import (
	"math/rand"
	"time"
	"database/sql"
	"fmt"
	"github.com/erasche/gologme"
	_ "github.com/mattn/go-sqlite3"
	"log"
	"net"
	"net/http"
	"net/rpc"
)

type Golog struct {
	Db *sql.DB
}

func (t *Golog) logToDb(uid int, windowlogs []gologme.WindowLogs, keylogs []gologme.KeyLogs, wll int){
	tx, err := t.Db.Begin()
	if err != nil {
		log.Fatal(err)
	}
	stmt, err := tx.Prepare("insert into windowLogs (time, name) values (?, ?)")
	if err != nil {
		log.Fatal(err)
	}
	defer stmt.Close()

	log.Printf("%d logs from [%d]\n", wll, uid)
	for i, w := range windowlogs {
		_, err = stmt.Exec(w.Time.Unix(), w.Name)
		if err != nil {
			log.Fatal(err)
		}
		if i >= wll - 1 {
			break
		}
	}

	tx.Commit()
}

func (t *Golog) ensureAuth(user string, key string) (int, error) {
	// Pretty assuredly not safe from timing attacks.
	stmt, err := t.Db.Prepare("select id from users where username = ? and api_key = ?")
	if err != nil {
		return -1, err
	}
	defer stmt.Close()

	// Maybe helps against timing attacks? Hmm.
	time.Sleep(time.Duration(rand.Int31n(1000)) * time.Millisecond)

	var uid int
	err = stmt.QueryRow(user, key).Scan(&uid)
	if err != nil {
		return -1, err
	}

	return uid, nil
}

func (t *Golog) Log(args gologme.RpcArgs, result *gologme.Result) error {
	uid, err := t.ensureAuth(args.User, args.ApiKey)
	if err != nil {
		log.Fatal(err)
		*result = 1
		return nil
	} else {
		log.Printf("%s authenticated successfully as uid %d\n", args.User, uid)
	}

	t.logToDb(
		uid,
		args.Windows,
		args.KeyLogs,
		args.WindowLogsLength,
	)

	*result = 0
	return nil
}

func (t *Golog) setupDb(db *sql.DB) {
	dbCreation := `
	create table if not exists users (
		id integer not null primary key autoincrement,
		username text,
		api_key text
	);

	create table if not exists windowLogs (
		id integer not null primary key autoincrement,
		uid integer,
		time integer,
		name text,
		foreign key (uid) references users(id)
	)

	create table if not exists keyLogs (
		id integer not null primary key autoincrement,
		uid integer,
		time integer,
		count integer,
		foreign key (uid) references users(id)
	)
	`

	_, err := db.Exec(dbCreation)
	if err != nil {
		log.Fatal(err)
	}
	t.Db = db
}

func main() {
	db, err := sql.Open("sqlite3", "file.db")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	golog := new(Golog)
	golog.setupDb(db)

	rpc.Register(golog)
	rpc.HandleHTTP()
	l, err := net.Listen("tcp", ":8080")
	if err != nil {
		log.Fatal("listen error:", err)
	}
	fmt.Println("Listening...")

	err = http.Serve(l, nil)
	if err != nil {
		log.Fatal("Error serving:", err)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	//"io"
	"net"
	"net/http"
	//"os"
	"log"
	"time"
)

type Listener interface {
	LastReceived() uint64 // timestamp

}
type Ship struct {
}

// three sources
// scaling: if parsing takes longer than dead time between messages, need to send to group
//

type Packet struct {
	source   string
	received time.Time
	data     []byte
}

func main() {
	writer := make(chan Packet)
	send := make(chan string)
	readAIS(send)
	go ReadHttp("ECC", "http://aishub.ais.ecc.no/raw", writer)
	go ReadTCP("Kystverket", "153.44.253.27:5631", writer)
	for packet := range writer {
		splitPacket(packet.data, send)
		//line := string(packet.data) // TODO split just in case
		//fmt.Printf("Packet with lenght %d from %s:\n%s", len(line), packet.source, line)
		if len(writer) == 20 {
			fmt.Printf("channel has backlog")
		}
	}
}

func WatchBuffer(buffer chan Packet) {

}

func ReadTCP(name string, ip string, writer chan Packet) {
	for {
		addr, err := net.ResolveTCPAddr("tcp", ip)
		CheckErr(err, "Resolve tcp address")
		conn, err := net.DialTCP("tcp", nil, addr)
		CheckErr(err, "listen to tcp")
		defer conn.Close() // FIXME can fail
		//conn.CloseWrite()
		buf := make([]byte, 4096)
		for {
			conn.SetReadDeadline(time.Now().Add(5 * time.Second))
			n, err := conn.Read(buf)
			if err != nil {
				log.Printf("\n\n\n%s read error: %s\n", name, err.Error())
				break
			} else {
				writer <- Packet{
					source:   name,
					received: time.Now(),
					data:     buf[0:n],
				}
			}
		}
	}
}

func ReadHttp(name string, url string, writer chan Packet) {
	client := http.Client{
		Transport:     nil,
		Jar:           nil,
		CheckRedirect: nil, // TODO log
		Timeout:       0,   // From start of connection
	}
	for {
		request, err := http.NewRequest("GET", url, nil)
		CheckErr(err, "Create request")
		stopper := make(chan struct{})
		go stopAfter(2, stopper)
		request.Cancel = stopper
		resp, err := client.Do(request)
		CheckErr(err, "connect to eccs receiver")
		defer resp.Body.Close()
		fmt.Println(resp)
		buf := make([]byte, 4096)
		for {
			n, err := resp.Body.Read(buf)
			if err != nil {
				log.Printf("\n\n\n%s read error: %s\n", name, err.Error())
				break
			} else {
				writer <- Packet{
					source:   name,
					received: time.Now(),
					data:     buf[0:n],
				}
			}
		}
	}
}

func stopAfter(seconds int, stopper chan struct{}) {
	tickCh := time.Tick(time.Duration(seconds) * time.Second)
	_ = <-tickCh
	stopper <- struct{}{}
}

func CheckErr(err error, msg string) {
	if err != nil {
		log.Fatalf("Failed to %s: %s\n", msg, err.Error())
	}
}

func ErrIf(cond bool, msg string) {
	if cond {
		log.Fatalln(msg)
	}
}
<commit_msg>Server reconnects on timeout but leaks connections at source<commit_after>package main

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

type Listener interface {
	LastReceived() uint64 // timestamp
}
type Ship struct {
}

// three sources
// scaling: if parsing takes longer than dead time between messages, need to send to group
//

type TimeoutConn struct {
	net.Conn
	timeout time.Duration
}

func (c *TimeoutConn) Read(buf []byte) (int, error) {
	c.SetReadDeadline(time.Now().Add(c.timeout))
	return c.Conn.Read(buf)
}
func NewTimeoutConnDialer(timeout time.Duration) func(context.Context, string, string) (net.Conn, error) {
	return func(_ context.Context, netw, addr string) (net.Conn, error) {
		conn, err := net.DialTimeout(netw, addr, time.Second*5)
		tconn := TimeoutConn{
			Conn:    conn,
			timeout: timeout,
		}
		return &tconn, err
	}
}

type Packet struct {
	source   string
	received time.Time
	data     []byte
}

func main() {
	writer := make(chan Packet)
	send := make(chan string)
	readAIS(send)
	go ReadHttp("ECC", "http://aishub.ais.ecc.no/raw", 5*time.Second, writer)
	go ReadTCP("Kystverket", "153.44.253.27:5631", 5*time.Second, writer)
	//go ReadHttp("test_timeout", "http://127.0.0.1:12345", 8*time.Second, writer)
	//go ReadTCP("test_timeout", "127.0.0.1:12345", 2*time.Second, writer)
	for packet := range writer {
		splitPacket(packet.data, send)
		//line := string(packet.data) // TODO split just in case
		//fmt.Printf("Packet with lenght %d from %s:\n%s", len(line), packet.source, line)
		if len(writer) == 20 {
			fmt.Printf("channel has backlog")
		}
	}
}

func WatchBuffer(buffer chan Packet) {

}

func ReadTCP(name string, ip string, silence_timeout time.Duration, writer chan Packet) {
	for {
		addr, err := net.ResolveTCPAddr("tcp", ip)
		CheckErr(err, "Resolve tcp address")
		conn, err := net.DialTCP("tcp", nil, addr)
		CheckErr(err, "listen to tcp")
		defer conn.Close() // FIXME can fail
		//conn.CloseWrite()
		buf := make([]byte, 4096)
		for {
			conn.SetReadDeadline(time.Now().Add(silence_timeout))
			n, err := conn.Read(buf)
			if err != nil {
				log.Printf("\n\n\n%s read error: %s\n", name, err.Error())
				break
			} else {
				writer <- Packet{
					source:   name,
					received: time.Now(),
					data:     buf[0:n],
				}
			}
		}
	}
}

func ReadHttp(name string, url string, silence_timeout time.Duration, writer chan Packet) {
	transport := (http.DefaultTransport.(*http.Transport)) // Clone it
	transport.DialContext = NewTimeoutConnDialer(silence_timeout)
	client := http.Client{
		Transport:     transport,
		Jar:           nil,
		CheckRedirect: nil, // TODO log
		Timeout:       0,   // Counts from start of connection
	}
	for {
		request, err := http.NewRequest("GET", url, nil)
		CheckErr(err, "Create request")
		resp, err := client.Do(request)
		CheckErr(err, fmt.Sprintf("connect to %ss receiver", name))
		defer resp.Body.Close()
		// Body is only ReadCloser, and GzipReader isn't Conn so type asserting won't work.
		// If it did we could set its timeout directly
		// We could also check and branch to two different implementations.
		// if resp.Body.(net.Conn) != nil {
		// 	fmt.Printf("http.Response.Body is a %T\n", resp.Body)
		// }

		buf := make([]byte, 4096)
		for {
			n, err := resp.Body.Read(buf)
			if err != nil {
				log.Printf("\n\n\n%s read error: %s\n", name, err.Error())
				break
			} else {
				writer <- Packet{
					source:   name,
					received: time.Now(),
					data:     buf[0:n],
				}
			}
		}
	}
}

func CheckErr(err error, msg string) {
	if err != nil {
		log.Fatalf("Failed to %s: %s\n", msg, err.Error())
	}
}

func ErrIf(cond bool, msg string) {
	if cond {
		log.Fatalln(msg)
	}
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"crypto/sha256"
	"encoding/json"
	"flag"
	"fmt"
	"gnat"
	"log"
	"net/http"
	"os/exec"

	"strings"

	"time"

	"os"

	"github.com/ccding/go-stun/stun"
	b58 "github.com/jbenet/go-base58"
)

// cap on how many routing nodes
// should be remembered
var maxRouteCacheSize = 500

// dht of peer GNAT nodes
var dht *gnat.DHT

// websocket hub to handle client messages
var hub *Hub

// mapping of ip addresses to gnat peers
var forwardingCache map[string]*gnat.NetworkNode

func main() {

	printWelcomeMessage()

	forwardingCache = make(map[string]*gnat.NetworkNode)

	// test the network to discovery what type of NAT (if any)
	// the client is behind.
	fmt.Print("1) Testing network...")
	nat, host, err := stun.NewClient().Discover()
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: a problem occured while testing your network.")
		fmt.Fprintf(os.Stderr, "Try again later.")
		os.Exit(1)
	}
	fmt.Println("done.")

	var hostAddr string
	if host == nil {
		out, _ := exec.Command("curl ipinfo.io/ip").Output()
		hostAddr = string(out)
	} else {
		hostAddr = host.String()
	}

	// make sure network is behind leniant NAT
	fmt.Println("  Network NAT configuration detected: " + nat.String())
	fmt.Println("  Public IP address: " + hostAddr)
	if nat == stun.NATNone || nat == stun.NATFull || nat == stun.NATPortRestricted {

		// generate an ID from the digest of the IP addr
		selfIP := strings.Split(hostAddr, ":")[0]
		ipDigest := sha256.Sum256([]byte(selfIP))

		// initialize the GNAT dht node
		initializeDHT(ipDigest[:])

		// listen for clients
		setupServer("127.0.0.1:2222")

		fmt.Println("GNAT node running!")

	} else {
		fmt.Fprintf(os.Stderr, "error: your network configuration does not support running a GNAT node.")
		fmt.Fprintf(os.Stderr, "Update your router/firewall settings to be less restrictive and try again.")
		os.Exit(1)
	}
}

func sendMessageToClient(sendToIP string, message []byte) error {
	return hub.sendMessageToClient(sendToIP, message)
}

func aknowledgementHandler(success bool, errCode int, errMsg string) {
	fmt.Printf("Did forward: %v, %v\n", success, errMsg)
}

func forwardingRequestHandler(fromIP string, header map[string]string, data []byte) {

	sendTo := header["to"]
	if sendTo == "" {
		return
	}

	ipDigest := sha256.Sum256([]byte(sendTo))
	id := b58.Encode(ipDigest[:])

	fmt.Println("Received forwarding request from " + fromIP)

	msg := make(map[string]string)
	msg["from"] = fromIP
	msg["ts"] = time.Now().Format(time.RFC3339)
	msgHeader, _ := json.Marshal(msg)

	var err error
	var foundNode *gnat.NetworkNode
	if node, ok := forwardingCache[id]; ok {
		foundNode = node
	} else {
		fmt.Println("Performing Kademlia.FIND_NODE operation")
		foundNode, err = dht.FindNode(id)
		forwardingCache[id] = foundNode

		// if cache too big, reset it
		if len(forwardingCache) > maxRouteCacheSize {
			forwardingCache = make(map[string]*gnat.NetworkNode)
		}
	}

	if err != nil {
		fmt.Println(err.Error())
	} else {
		fmt.Println("Forwarding data to " + foundNode.IP.String())
		dht.ForwardDataVia(foundNode, gnat.NewNetworkNode(sendTo, "0"), append(msgHeader, data...), aknowledgementHandler)
	}
}

func handConnectionRequest(w http.ResponseWriter, r *http.Request) {

	// generate digest hash of IP address
	clientIP := strings.Split(r.RemoteAddr, ":")[0]
	ipDigest := sha256.Sum256([]byte(clientIP))
	id := b58.Encode(ipDigest[:])

	// find the node connected to this client ip
	node, err := dht.FindNode(id)

	if err == nil {
		if bytes.Compare(node.ID, dht.GetSelfID()) == 0 {
			fmt.Println("New connection from " + r.RemoteAddr)

			if r.URL.Path != "/" {
				http.Error(w, "Not found", 404)
				return
			}

			if r.Method != "GET" {
				http.Error(w, "Method not allowed", 405)
				return
			}

			http.ServeFile(w, r, "./static/home.html")

		} else {
			fmt.Println("Redirecting " + r.RemoteAddr + " to http://" + node.IP.String() + ":2222")
			http.Redirect(w, r, "http://"+node.IP.String()+":2222", 301)
		}

	} else {
		fmt.Println(err)
	}
}

func setupServer(host string) {

	fmt.Print("4) Setting up HTTP server...")
	flag.Parse()
	hub = newHub()
	go hub.run(forwardingRequestHandler)
	http.HandleFunc("/", handConnectionRequest)
	http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
		serveWs(hub, w, r)
	})
	fmt.Println("done")
	fmt.Println("Listening on " + host)
	err := http.ListenAndServe(":2222", nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

func initializeDHT(selfID []byte) {
	var ip = flag.String("ip", "0.0.0.0", "IP address to use")
	var port = flag.String("port", "1443", "Port to use")
	var bIP = flag.String("bip", "45.55.18.163", "IP address of bootstrap server")
	var bPort = flag.String("bport", "1443", "Port of bootstrap server")
	var stun = flag.Bool("stun", true, "Use STUN")

	flag.Parse()

	var bootstrapNodes []*gnat.NetworkNode
	if *bIP != "" || *bPort != "" {
		bootstrapNode := gnat.NewNetworkNode(*bIP, *bPort)
		bootstrapNodes = append(bootstrapNodes, bootstrapNode)
	}

	var err error
	dht, err = gnat.NewDHT(&gnat.Options{
		BootstrapNodes:    bootstrapNodes,
		IP:                *ip,
		ID:                selfID,
		Port:              *port,
		UseStun:           *stun,
		ForwardingHandler: sendMessageToClient,
	})

	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Print("2) Opening socket...")

	err = dht.CreateSocket()
	if err != nil {
		panic(err)
	}

	fmt.Println("done")
	go func() {
		err := dht.Listen()
		panic(err)
	}()

	if len(bootstrapNodes) > 0 {
		fmt.Print("3) Bootstrapping into GNAT network...")
		dht.Bootstrap()
		fmt.Println("done")
	} else {
		fmt.Println("3) Skipping GNAT bootstrap")
	}
}

func printWelcomeMessage() {
	fmt.Println("\n  _____ _   _       _______  ")
	fmt.Println(" / ____| \\ | |   /\\|__   __|")
	fmt.Println("| |  __|  \\| |  /  \\  | |")
	fmt.Println("| | |_ | . ` | / /\\ \\ | |")
	fmt.Println("| |__| | |\\  |/ ____ \\| |")
	fmt.Println(" \\_____|_| \\_/_/    \\_\\_|")
	fmt.Println("  GNAT Server Node v0.0.1")
	fmt.Println("    *Documentation:   https://gnat.cs.brown.edu/docs")
	fmt.Println("    *Support:         https://gnat.cs.brown.edu/support")
	fmt.Println("    *GitHub:          https://github.com/ogisan/gnat")
	fmt.Println("    For more information, visit: http://gnat.cs.brown.edu")
}
<commit_msg>updated whitelisted nats<commit_after>package main

import (
	"bytes"
	"crypto/sha256"
	"encoding/json"
	"flag"
	"fmt"
	"gnat"
	"log"
	"net/http"
	"os/exec"

	"strings"

	"time"

	"os"

	"github.com/ccding/go-stun/stun"
	b58 "github.com/jbenet/go-base58"
)

// cap on how many routing nodes
// should be remembered
var maxRouteCacheSize = 500

// dht of peer GNAT nodes
var dht *gnat.DHT

// websocket hub to handle client messages
var hub *Hub

// mapping of ip addresses to gnat peers
var forwardingCache map[string]*gnat.NetworkNode

func main() {

	printWelcomeMessage()

	forwardingCache = make(map[string]*gnat.NetworkNode)

	// test the network to discovery what type of NAT (if any)
	// the client is behind.
	fmt.Print("1) Testing network...")
	nat, host, err := stun.NewClient().Discover()
	if err != nil {
		fmt.Fprintf(os.Stderr, "error: a problem occured while testing your network.")
		fmt.Fprintf(os.Stderr, "Try again later.")
		os.Exit(1)
	}
	fmt.Println("done.")

	var hostAddr string
	if host == nil {
		out, _ := exec.Command("curl ipinfo.io/ip").Output()
		hostAddr = string(out)
	} else {
		hostAddr = host.String()
	}

	// make sure network is behind leniant NAT
	fmt.Println("  Network NAT configuration detected: " + nat.String())
	fmt.Println("  Public IP address: " + hostAddr)
	if nat == stun.NATNone || nat == stun.NATFull || nat == stun.NATPortRestricted || nat == stun.NATSymetricUDPFirewall {

		// generate an ID from the digest of the IP addr
		selfIP := strings.Split(hostAddr, ":")[0]
		ipDigest := sha256.Sum256([]byte(selfIP))

		// initialize the GNAT dht node
		initializeDHT(ipDigest[:])

		// listen for clients
		setupServer("127.0.0.1:2222")

		fmt.Println("GNAT node running!")

	} else {
		fmt.Fprintf(os.Stderr, "error: your network configuration does not support running a GNAT node.")
		fmt.Fprintf(os.Stderr, "Update your router/firewall settings to be less restrictive and try again.")
		os.Exit(1)
	}
}

func sendMessageToClient(sendToIP string, message []byte) error {
	return hub.sendMessageToClient(sendToIP, message)
}

func aknowledgementHandler(success bool, errCode int, errMsg string) {
	fmt.Printf("Did forward: %v, %v\n", success, errMsg)
}

func forwardingRequestHandler(fromIP string, header map[string]string, data []byte) {

	sendTo := header["to"]
	if sendTo == "" {
		return
	}

	ipDigest := sha256.Sum256([]byte(sendTo))
	id := b58.Encode(ipDigest[:])

	fmt.Println("Received forwarding request from " + fromIP)

	msg := make(map[string]string)
	msg["from"] = fromIP
	msg["ts"] = time.Now().Format(time.RFC3339)
	msgHeader, _ := json.Marshal(msg)

	var err error
	var foundNode *gnat.NetworkNode
	if node, ok := forwardingCache[id]; ok {
		foundNode = node
	} else {
		fmt.Println("Performing Kademlia.FIND_NODE operation")
		foundNode, err = dht.FindNode(id)
		forwardingCache[id] = foundNode

		// if cache too big, reset it
		if len(forwardingCache) > maxRouteCacheSize {
			forwardingCache = make(map[string]*gnat.NetworkNode)
		}
	}

	if err != nil {
		fmt.Println(err.Error())
	} else {
		fmt.Println("Forwarding data to " + foundNode.IP.String())
		dht.ForwardDataVia(foundNode, gnat.NewNetworkNode(sendTo, "0"), append(msgHeader, data...), aknowledgementHandler)
	}
}

func handConnectionRequest(w http.ResponseWriter, r *http.Request) {

	// generate digest hash of IP address
	clientIP := strings.Split(r.RemoteAddr, ":")[0]
	ipDigest := sha256.Sum256([]byte(clientIP))
	id := b58.Encode(ipDigest[:])

	// find the node connected to this client ip
	node, err := dht.FindNode(id)

	if err == nil {
		if bytes.Compare(node.ID, dht.GetSelfID()) == 0 {
			fmt.Println("New connection from " + r.RemoteAddr)

			if r.URL.Path != "/" {
				http.Error(w, "Not found", 404)
				return
			}

			if r.Method != "GET" {
				http.Error(w, "Method not allowed", 405)
				return
			}

			http.ServeFile(w, r, "./static/home.html")

		} else {
			fmt.Println("Redirecting " + r.RemoteAddr + " to http://" + node.IP.String() + ":2222")
			http.Redirect(w, r, "http://"+node.IP.String()+":2222", 301)
		}

	} else {
		fmt.Println(err)
	}
}

func setupServer(host string) {

	fmt.Print("4) Setting up HTTP server...")
	flag.Parse()
	hub = newHub()
	go hub.run(forwardingRequestHandler)
	http.HandleFunc("/", handConnectionRequest)
	http.HandleFunc("/ws", func(w http.ResponseWriter, r *http.Request) {
		serveWs(hub, w, r)
	})
	fmt.Println("done")
	fmt.Println("Listening on " + host)
	err := http.ListenAndServe(":2222", nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}

func initializeDHT(selfID []byte) {
	var ip = flag.String("ip", "0.0.0.0", "IP address to use")
	var port = flag.String("port", "1443", "Port to use")
	var bIP = flag.String("bip", "45.55.18.163", "IP address of bootstrap server")
	var bPort = flag.String("bport", "1443", "Port of bootstrap server")
	var stun = flag.Bool("stun", true, "Use STUN")

	flag.Parse()

	var bootstrapNodes []*gnat.NetworkNode
	if *bIP != "" || *bPort != "" {
		bootstrapNode := gnat.NewNetworkNode(*bIP, *bPort)
		bootstrapNodes = append(bootstrapNodes, bootstrapNode)
	}

	var err error
	dht, err = gnat.NewDHT(&gnat.Options{
		BootstrapNodes:    bootstrapNodes,
		IP:                *ip,
		ID:                selfID,
		Port:              *port,
		UseStun:           *stun,
		ForwardingHandler: sendMessageToClient,
	})

	if err != nil {
		fmt.Println(err)
		return
	}

	fmt.Print("2) Opening socket...")

	err = dht.CreateSocket()
	if err != nil {
		panic(err)
	}

	fmt.Println("done")
	go func() {
		err := dht.Listen()
		panic(err)
	}()

	if len(bootstrapNodes) > 0 {
		fmt.Print("3) Bootstrapping into GNAT network...")
		dht.Bootstrap()
		fmt.Println("done")
	} else {
		fmt.Println("3) Skipping GNAT bootstrap")
	}
}

func printWelcomeMessage() {
	fmt.Println("\n  _____ _   _       _______  ")
	fmt.Println(" / ____| \\ | |   /\\|__   __|")
	fmt.Println("| |  __|  \\| |  /  \\  | |")
	fmt.Println("| | |_ | . ` | / /\\ \\ | |")
	fmt.Println("| |__| | |\\  |/ ____ \\| |")
	fmt.Println(" \\_____|_| \\_/_/    \\_\\_|")
	fmt.Println("  GNAT Server Node v0.0.1")
	fmt.Println("    *Documentation:   https://gnat.cs.brown.edu/docs")
	fmt.Println("    *Support:         https://gnat.cs.brown.edu/support")
	fmt.Println("    *GitHub:          https://github.com/ogisan/gnat")
	fmt.Println("    For more information, visit: http://gnat.cs.brown.edu")
}
<|endoftext|>


<commit_before>package models

type Place struct {
    Id          int     `form:"-"`
    Name        string  `form:"name" valid:"Required;AlphaNumeric;MinSize(3);MaxSize(50)"`
    Description string  `form:"description" valid:"MaxSize(600)"`
    Website     string  `form:"website"`
    Latitude    float64 `form:"latitude"`
    Longitude   float64 `form:"longitude"`
    Type        int     `form:"-"`
}

func (p *Place) TableName() string {
    return "places"
}<commit_msg>Changed to uint and uint8 to match database structure<commit_after>package models

type Place struct {
    Id          uint    `form:"-"`
    Name        string  `form:"name" valid:"Required;AlphaNumeric;MinSize(3);MaxSize(50)"`
    Description string  `form:"description" valid:"MaxSize(600)"`
    Website     string  `form:"website"`
    Latitude    float64 `form:"latitude"`
    Longitude   float64 `form:"longitude"`
    Type        uint8   `form:"-"`
}

func (p *Place) TableName() string {
    return "places"
}<|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2016 Maciej Borzecki

// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package models

import (
	"github.com/bboozzoo/q3stats/store"
	"github.com/jinzhu/gorm"
)

// Registered players
type Player struct {
	gorm.Model

	// user defined name, ex. joe
	Name string

	// password hash
	PasswordHash string
}

// create new player returning its ID
func NewPlayer(store store.DB, name string, passwordhash string) uint {
	player := Player{
		Name:         name,
		PasswordHash: passwordhash,
	}

	db := store.Conn()

	db.Create(&player)

	return player.ID
}

func HasPlayer(store store.DB, name string) bool {
	db := store.Conn()

	var player Player

	notfound := db.Where(&Player{Name: name}).
		First(&player).
		RecordNotFound()

	if notfound == true {
		return false
	}
	return true
}
<commit_msg>models/player: helper for listing players<commit_after>// The MIT License (MIT)

// Copyright (c) 2016 Maciej Borzecki

// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:

// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package models

import (
	"github.com/bboozzoo/q3stats/store"
	"github.com/jinzhu/gorm"
)

// Registered players
type Player struct {
	gorm.Model

	// user defined name, ex. joe
	Name string

	// password hash
	PasswordHash string
}

// create new player returning its ID
func NewPlayer(store store.DB, name string, passwordhash string) uint {
	player := Player{
		Name:         name,
		PasswordHash: passwordhash,
	}

	db := store.Conn()

	db.Create(&player)

	return player.ID
}

func HasPlayer(store store.DB, name string) bool {
	db := store.Conn()

	var player Player

	notfound := db.Where(&Player{Name: name}).
		First(&player).
		RecordNotFound()

	if notfound == true {
		return false
	}
	return true
}

func ListPlayers(store store.DB) []Player {
	db := store.Conn()

	var players []Player
	db.Find(&players)

	return players
}
<|endoftext|>


<commit_before>package models

import (
	"log"

	"github.com/jmoiron/sqlx"
)

// SearchModel provides functionality to search recipes.
type SearchModel struct {
	*Model
}

// SearchFilter is the primary model class for recipe search
type SearchFilter struct {
	Query string
	Tags  []string
}

// Find retrieves all recipes matching the specified search filter and within the range specified,
// sorted by name.
func (m *SearchModel) Find(filter SearchFilter, page int64, count int64) (*Recipes, int64, error) {
	var total int64
	var search string
	if filter.Query == "" {
		search = "%"
	} else {
		search = "%" + filter.Query + "%"
	}
	var like string
	switch m.cfg.DatabaseDriver {
	case "sqlite3":
		like = "LIKE"
	case "postgres":
		like = "ILIKE"
	}
	partialStmt := "FROM recipe AS r " +
		"LEFT OUTER JOIN recipe_tag AS t ON t.recipe_id = r.id " +
		"LEFT OUTER JOIN recipe_rating AS g ON g.recipe_id = r.id " +
		"WHERE (r.name " + like + " ? OR r.Ingredients " + like + " ? OR r.directions " + like + " ? OR t.tag " + like + " ?)"
	if len(filter.Tags) > 0 {
		partialStmt = partialStmt + " AND (t.tag IN (?))"
	}

	countStmt := "SELECT count(DISTINCT r.id) " + partialStmt
	var err error
	var countArgs []interface{}
	if len(filter.Tags) == 0 {
		countStmt, countArgs, err = sqlx.In(countStmt, search, search, search, search)
	} else {
		countStmt, countArgs, err = sqlx.In(countStmt, search, search, search, search, filter.Tags)
	}
	if err != nil {
		return nil, 0, err
	}
	countStmt = m.db.Rebind(countStmt)
	log.Printf("[search] " + countStmt)
	row := m.db.QueryRow(countStmt, countArgs...)
	if err := row.Scan(&total); err != nil {
		return nil, 0, err
	}

	offset := count * (page - 1)
	selectStmt := "SELECT DISTINCT " +
		"r.id, r.name, r.serving_size, r.nutrition_info, r.ingredients, r.directions, COALESCE(g.rating, 0) " +
		partialStmt +
		" ORDER BY r.name LIMIT ? OFFSET ?"
	var selectArgs []interface{}
	if len(filter.Tags) == 0 {
		selectStmt, selectArgs, err = sqlx.In(selectStmt, search, search, search, search, count, offset)
	} else {
		selectStmt, selectArgs, err = sqlx.In(selectStmt, search, search, search, search, filter.Tags, count, offset)
	}
	if err != nil {
		return nil, 0, err
	}
	selectStmt = m.db.Rebind(selectStmt)
	log.Printf("[search] " + selectStmt)
	rows, err := m.db.Query(selectStmt, selectArgs...)
	if err != nil {
		return nil, 0, err
	}

	var recipes Recipes
	for rows.Next() {
		var recipe Recipe
		err = rows.Scan(
			&recipe.ID,
			&recipe.Name,
			&recipe.ServingSize,
			&recipe.NutritionInfo,
			&recipe.Ingredients,
			&recipe.Directions,
			&recipe.AvgRating)
		if err != nil {
			return nil, 0, err
		}

		imgs, err := m.Images.List(recipe.ID)
		if err != nil {
			return nil, 0, err
		}
		if len(*imgs) > 0 {
			recipe.Image = (*imgs)[0].ThumbnailURL
		}

		recipes = append(recipes, recipe)
	}

	return &recipes, total, nil
}
<commit_msg>Removed several extra log statements.<commit_after>package models

import "github.com/jmoiron/sqlx"

// SearchModel provides functionality to search recipes.
type SearchModel struct {
	*Model
}

// SearchFilter is the primary model class for recipe search
type SearchFilter struct {
	Query string
	Tags  []string
}

// Find retrieves all recipes matching the specified search filter and within the range specified,
// sorted by name.
func (m *SearchModel) Find(filter SearchFilter, page int64, count int64) (*Recipes, int64, error) {
	var total int64
	var search string
	if filter.Query == "" {
		search = "%"
	} else {
		search = "%" + filter.Query + "%"
	}
	var like string
	switch m.cfg.DatabaseDriver {
	case "sqlite3":
		like = "LIKE"
	case "postgres":
		like = "ILIKE"
	}
	partialStmt := "FROM recipe AS r " +
		"LEFT OUTER JOIN recipe_tag AS t ON t.recipe_id = r.id " +
		"LEFT OUTER JOIN recipe_rating AS g ON g.recipe_id = r.id " +
		"WHERE (r.name " + like + " ? OR r.Ingredients " + like + " ? OR r.directions " + like + " ? OR t.tag " + like + " ?)"
	if len(filter.Tags) > 0 {
		partialStmt = partialStmt + " AND (t.tag IN (?))"
	}

	countStmt := "SELECT count(DISTINCT r.id) " + partialStmt
	var err error
	var countArgs []interface{}
	if len(filter.Tags) == 0 {
		countStmt, countArgs, err = sqlx.In(countStmt, search, search, search, search)
	} else {
		countStmt, countArgs, err = sqlx.In(countStmt, search, search, search, search, filter.Tags)
	}
	if err != nil {
		return nil, 0, err
	}
	countStmt = m.db.Rebind(countStmt)
	row := m.db.QueryRow(countStmt, countArgs...)
	if err := row.Scan(&total); err != nil {
		return nil, 0, err
	}

	offset := count * (page - 1)
	selectStmt := "SELECT DISTINCT " +
		"r.id, r.name, r.serving_size, r.nutrition_info, r.ingredients, r.directions, COALESCE(g.rating, 0) " +
		partialStmt +
		" ORDER BY r.name LIMIT ? OFFSET ?"
	var selectArgs []interface{}
	if len(filter.Tags) == 0 {
		selectStmt, selectArgs, err = sqlx.In(selectStmt, search, search, search, search, count, offset)
	} else {
		selectStmt, selectArgs, err = sqlx.In(selectStmt, search, search, search, search, filter.Tags, count, offset)
	}
	if err != nil {
		return nil, 0, err
	}
	selectStmt = m.db.Rebind(selectStmt)
	rows, err := m.db.Query(selectStmt, selectArgs...)
	if err != nil {
		return nil, 0, err
	}

	var recipes Recipes
	for rows.Next() {
		var recipe Recipe
		err = rows.Scan(
			&recipe.ID,
			&recipe.Name,
			&recipe.ServingSize,
			&recipe.NutritionInfo,
			&recipe.Ingredients,
			&recipe.Directions,
			&recipe.AvgRating)
		if err != nil {
			return nil, 0, err
		}

		imgs, err := m.Images.List(recipe.ID)
		if err != nil {
			return nil, 0, err
		}
		if len(*imgs) > 0 {
			recipe.Image = (*imgs)[0].ThumbnailURL
		}

		recipes = append(recipes, recipe)
	}

	return &recipes, total, nil
}
<|endoftext|>


<commit_before>package logic

import (
	"fmt"
	"go-bots/ev3"
	"go-bots/ui"
	"os"
)

func log(now int, dir ev3.Direction, msg string) {
	dirString := ""
	if dir == ev3.Left {
		dirString = "LEFT"
	} else if dir == ev3.Right {
		dirString = "RIGHT"
	} else {
		dirString = "NONE"
	}

	fmt.Fprintln(os.Stderr, now, dirString, msg)
}

func cmd() {
	commandProcessor(&c)
}

func handleTime(d Data, start int) (now int, elapsed int) {
	now = d.Millis
	c.Millis = now
	elapsed = now - start
	return
}

func speed(left int, right int) {
	c.SpeedLeft = left
	c.SpeedRight = right
}

func normalizeLedValue(v int) int {
	if v > 255 {
		v = 255
	}
	if v < 0 {
		v = 0
	}
	return v
}

func leds(leftGreen int, rightGreen int, leftRed int, rightRed int) {
	leftGreen = normalizeLedValue(leftGreen)
	rightGreen = normalizeLedValue(rightGreen)
	leftRed = normalizeLedValue(leftRed)
	rightRed = normalizeLedValue(rightRed)
	c.LedLeftGreen = leftGreen
	c.LedRightGreen = rightGreen
	c.LedLeftRed = leftRed
	c.LedRightRed = rightRed
}

func ledsFromData(d Data) {
	c.LedLeftGreen = 255 * d.IrLeftValue / 100
	c.LedRightGreen = 255 * d.IrRightValue / 100
	if d.CornerLeftIsOut {
		c.LedLeftRed = 255
	} else {
		c.LedLeftRed = 0
	}
	if d.CornerRightIsOut {
		c.LedRightRed = 255
	} else {
		c.LedRightRed = 0
	}
}

func checkDone(k ui.KeyEvent) bool {
	if k.Key == ui.Quit || k.Key == ui.Back {

		log(k.Millis, ev3.NoDirection, " *** DONE ***")

		go chooseStrategy(k.Millis)
		return true
	}
	return false
}
func checkQuit(k ui.KeyEvent) {
	if k.Key == ui.Quit || k.Key == ui.Back {
		quit <- true
		return
	}
}

func checkBorder(d Data, now int) bool {
	if d.CornerLeftIsOut {
		if d.CornerRightIsOut {
			go back(now, ev3.NoDirection)
			return true
		}
		go back(now, ev3.Left)
		return true
	}
	if d.CornerRightIsOut {
		if d.CornerLeftIsOut {
			go back(now, ev3.NoDirection)
			return true
		}
		go back(now, ev3.Right)
		return true
	}
	return false
}
<commit_msg>Keep leds off in xl4.<commit_after>package logic

import (
	"fmt"
	"go-bots/ev3"
	"go-bots/ui"
	"os"
)

func log(now int, dir ev3.Direction, msg string) {
	dirString := ""
	if dir == ev3.Left {
		dirString = "LEFT"
	} else if dir == ev3.Right {
		dirString = "RIGHT"
	} else {
		dirString = "NONE"
	}

	fmt.Fprintln(os.Stderr, now, dirString, msg)
}

func cmd() {
	commandProcessor(&c)
}

func handleTime(d Data, start int) (now int, elapsed int) {
	now = d.Millis
	c.Millis = now
	elapsed = now - start
	return
}

func speed(left int, right int) {
	c.SpeedLeft = left
	c.SpeedRight = right
}

func normalizeLedValue(v int) int {
	if v > 255 {
		v = 255
	}
	if v < 0 {
		v = 0
	}
	return v
}

func leds(leftGreen int, rightGreen int, leftRed int, rightRed int) {
	leftGreen = normalizeLedValue(leftGreen)
	rightGreen = normalizeLedValue(rightGreen)
	leftRed = normalizeLedValue(leftRed)
	rightRed = normalizeLedValue(rightRed)
	c.LedLeftGreen = leftGreen
	c.LedRightGreen = rightGreen
	c.LedLeftRed = leftRed
	c.LedRightRed = rightRed
}

func ledsFromData(d Data) {
	leds(0, 0, 0, 0)
	/*
		c.LedLeftGreen = 255 * d.IrLeftValue / 100
		c.LedRightGreen = 255 * d.IrRightValue / 100
		if d.CornerLeftIsOut {
			c.LedLeftRed = 255
		} else {
			c.LedLeftRed = 0
		}
		if d.CornerRightIsOut {
			c.LedRightRed = 255
		} else {
			c.LedRightRed = 0
		}
	*/
}

func checkDone(k ui.KeyEvent) bool {
	if k.Key == ui.Quit || k.Key == ui.Back {

		log(k.Millis, ev3.NoDirection, " *** DONE ***")

		go chooseStrategy(k.Millis)
		return true
	}
	return false
}
func checkQuit(k ui.KeyEvent) {
	if k.Key == ui.Quit || k.Key == ui.Back {
		quit <- true
		return
	}
}

func checkBorder(d Data, now int) bool {
	if d.CornerLeftIsOut {
		if d.CornerRightIsOut {
			go back(now, ev3.NoDirection)
			return true
		}
		go back(now, ev3.Left)
		return true
	}
	if d.CornerRightIsOut {
		if d.CornerLeftIsOut {
			go back(now, ev3.NoDirection)
			return true
		}
		go back(now, ev3.Right)
		return true
	}
	return false
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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 cache

import (
	"fmt"
	"os"
	"reflect"
	"strconv"
	"sync"
	"time"

	"k8s.io/klog"

	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/util/diff"
)

var mutationDetectionEnabled = false

func init() {
	mutationDetectionEnabled, _ = strconv.ParseBool(os.Getenv("KUBE_CACHE_MUTATION_DETECTOR"))
}

// MutationDetector is able to monitor if the object be modified outside.
type MutationDetector interface {
	AddObject(obj interface{})
	Run(stopCh <-chan struct{})
}

// NewCacheMutationDetector creates a new instance for the defaultCacheMutationDetector.
func NewCacheMutationDetector(name string) MutationDetector {
	if !mutationDetectionEnabled {
		return dummyMutationDetector{}
	}
	klog.Warningln("Mutation detector is enabled, this will result in memory leakage.")
	return &defaultCacheMutationDetector{name: name, period: 1 * time.Second}
}

type dummyMutationDetector struct{}

func (dummyMutationDetector) Run(stopCh <-chan struct{}) {
}
func (dummyMutationDetector) AddObject(obj interface{}) {
}

// defaultCacheMutationDetector gives a way to detect if a cached object has been mutated
// It has a list of cached objects and their copies.  I haven't thought of a way
// to see WHO is mutating it, just that it's getting mutated.
type defaultCacheMutationDetector struct {
	name   string
	period time.Duration

	lock       sync.Mutex
	cachedObjs []cacheObj

	// failureFunc is injectable for unit testing.  If you don't have it, the process will panic.
	// This panic is intentional, since turning on this detection indicates you want a strong
	// failure signal.  This failure is effectively a p0 bug and you can't trust process results
	// after a mutation anyway.
	failureFunc func(message string)
}

// cacheObj holds the actual object and a copy
type cacheObj struct {
	cached interface{}
	copied interface{}
}

func (d *defaultCacheMutationDetector) Run(stopCh <-chan struct{}) {
	// we DON'T want protection from panics.  If we're running this code, we want to die
	for {
		d.CompareObjects()

		select {
		case <-stopCh:
			return
		case <-time.After(d.period):
		}
	}
}

// AddObject makes a deep copy of the object for later comparison.  It only works on runtime.Object
// but that covers the vast majority of our cached objects
func (d *defaultCacheMutationDetector) AddObject(obj interface{}) {
	if _, ok := obj.(DeletedFinalStateUnknown); ok {
		return
	}
	if obj, ok := obj.(runtime.Object); ok {
		copiedObj := obj.DeepCopyObject()

		d.lock.Lock()
		defer d.lock.Unlock()
		d.cachedObjs = append(d.cachedObjs, cacheObj{cached: obj, copied: copiedObj})
	}
}

func (d *defaultCacheMutationDetector) CompareObjects() {
	d.lock.Lock()
	defer d.lock.Unlock()

	altered := false
	for i, obj := range d.cachedObjs {
		if !reflect.DeepEqual(obj.cached, obj.copied) {
			fmt.Printf("CACHE %s[%d] ALTERED!\n%v\n", d.name, i, diff.ObjectGoPrintSideBySide(obj.cached, obj.copied))
			altered = true
		}
	}

	if altered {
		msg := fmt.Sprintf("cache %s modified", d.name)
		if d.failureFunc != nil {
			d.failureFunc(msg)
			return
		}
		panic(msg)
	}
}
<commit_msg>Retain objects for a limited lifetime in the mutation cache detector by default<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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 cache

import (
	"fmt"
	"os"
	"reflect"
	"strconv"
	"sync"
	"time"

	"k8s.io/klog"

	"k8s.io/apimachinery/pkg/runtime"
	"k8s.io/apimachinery/pkg/util/diff"
)

var mutationDetectionEnabled = false

func init() {
	mutationDetectionEnabled, _ = strconv.ParseBool(os.Getenv("KUBE_CACHE_MUTATION_DETECTOR"))
}

// MutationDetector is able to monitor if the object be modified outside.
type MutationDetector interface {
	AddObject(obj interface{})
	Run(stopCh <-chan struct{})
}

// NewCacheMutationDetector creates a new instance for the defaultCacheMutationDetector.
func NewCacheMutationDetector(name string) MutationDetector {
	if !mutationDetectionEnabled {
		return dummyMutationDetector{}
	}
	klog.Warningln("Mutation detector is enabled, this will result in memory leakage.")
	return &defaultCacheMutationDetector{name: name, period: 1 * time.Second, retainDuration: 2 * time.Minute}
}

type dummyMutationDetector struct{}

func (dummyMutationDetector) Run(stopCh <-chan struct{}) {
}
func (dummyMutationDetector) AddObject(obj interface{}) {
}

// defaultCacheMutationDetector gives a way to detect if a cached object has been mutated
// It has a list of cached objects and their copies.  I haven't thought of a way
// to see WHO is mutating it, just that it's getting mutated.
type defaultCacheMutationDetector struct {
	name   string
	period time.Duration

	lock       sync.Mutex
	cachedObjs []cacheObj

	retainDuration     time.Duration
	lastRotated        time.Time
	retainedCachedObjs []cacheObj

	// failureFunc is injectable for unit testing.  If you don't have it, the process will panic.
	// This panic is intentional, since turning on this detection indicates you want a strong
	// failure signal.  This failure is effectively a p0 bug and you can't trust process results
	// after a mutation anyway.
	failureFunc func(message string)
}

// cacheObj holds the actual object and a copy
type cacheObj struct {
	cached interface{}
	copied interface{}
}

func (d *defaultCacheMutationDetector) Run(stopCh <-chan struct{}) {
	// we DON'T want protection from panics.  If we're running this code, we want to die
	for {
		if d.lastRotated.IsZero() {
			d.lastRotated = time.Now()
		} else if time.Now().Sub(d.lastRotated) > d.retainDuration {
			d.retainedCachedObjs = d.cachedObjs
			d.cachedObjs = nil
			d.lastRotated = time.Now()
		}

		d.CompareObjects()

		select {
		case <-stopCh:
			return
		case <-time.After(d.period):
		}
	}
}

// AddObject makes a deep copy of the object for later comparison.  It only works on runtime.Object
// but that covers the vast majority of our cached objects
func (d *defaultCacheMutationDetector) AddObject(obj interface{}) {
	if _, ok := obj.(DeletedFinalStateUnknown); ok {
		return
	}
	if obj, ok := obj.(runtime.Object); ok {
		copiedObj := obj.DeepCopyObject()

		d.lock.Lock()
		defer d.lock.Unlock()
		d.cachedObjs = append(d.cachedObjs, cacheObj{cached: obj, copied: copiedObj})
	}
}

func (d *defaultCacheMutationDetector) CompareObjects() {
	d.lock.Lock()
	defer d.lock.Unlock()

	altered := false
	for i, obj := range d.cachedObjs {
		if !reflect.DeepEqual(obj.cached, obj.copied) {
			fmt.Printf("CACHE %s[%d] ALTERED!\n%v\n", d.name, i, diff.ObjectGoPrintSideBySide(obj.cached, obj.copied))
			altered = true
		}
	}
	for i, obj := range d.retainedCachedObjs {
		if !reflect.DeepEqual(obj.cached, obj.copied) {
			fmt.Printf("CACHE %s[%d] ALTERED!\n%v\n", d.name, i, diff.ObjectGoPrintSideBySide(obj.cached, obj.copied))
			altered = true
		}
	}

	if altered {
		msg := fmt.Sprintf("cache %s modified", d.name)
		if d.failureFunc != nil {
			d.failureFunc(msg)
			return
		}
		panic(msg)
	}
}
<|endoftext|>


<commit_before>package xpc

/*
#include "xpc_wrapper_darwin.h"
#include "sys/utsname.h"
*/
import "C"

import (
	"errors"
	"fmt"
	"log"
	r "reflect"
	"unsafe"
)

type XPC struct {
	conn C.xpc_connection_t
}

func (x *XPC) Send(msg interface{}, verbose bool) {
	// verbose == true converts the type from bool to C._Bool
	C.XpcSendMessage(x.conn, goToXpc(msg), true, verbose == true)
}

//
// minimal XPC support required for BLE
//

// a dictionary of things
type Dict map[string]interface{}

func (d Dict) Contains(k string) bool {
	_, ok := d[k]
	return ok
}

func (d Dict) MustGetDict(k string) Dict {
	return d[k].(Dict)
}

func (d Dict) MustGetArray(k string) Array {
	return d[k].(Array)
}

func (d Dict) MustGetBytes(k string) []byte {
	return d[k].([]byte)
}

func (d Dict) MustGetHexBytes(k string) string {
	return fmt.Sprintf("%x", d[k].([]byte))
}

func (d Dict) MustGetInt(k string) int {
	return int(d[k].(int64))
}

func (d Dict) MustGetUUID(k string) []byte {
	u := d[k].(UUID)
	return u[:]
}

func (d Dict) GetString(k, defv string) string {
	if v := d[k]; v != nil {
		//log.Printf("GetString %s %#v\n", k, v)
		return v.(string)
	} else {
		//log.Printf("GetString %s default %#v\n", k, defv)
		return defv
	}
}

func (d Dict) GetBytes(k string, defv []byte) []byte {
	if v := d[k]; v != nil {
		//log.Printf("GetBytes %s %#v\n", k, v)
		return v.([]byte)
	} else {
		//log.Printf("GetBytes %s default %#v\n", k, defv)
		return defv
	}
}

func (d Dict) GetInt(k string, defv int) int {
	if v := d[k]; v != nil {
		//log.Printf("GetString %s %#v\n", k, v)
		return int(v.(int64))
	} else {
		//log.Printf("GetString %s default %#v\n", k, defv)
		return defv
	}
}

func (d Dict) GetUUID(k string) UUID {
	return GetUUID(d[k])
}

// an array of things
type Array []interface{}

func (a Array) GetUUID(k int) UUID {
	return GetUUID(a[k])
}

// a UUID
type UUID []byte

func MakeUUID(s string) UUID {
	var sl []byte
	fmt.Sscanf(s, "%32x", &sl)

	var uuid [16]byte
	copy(uuid[:], sl)
	return UUID(uuid[:])
}

func (uuid UUID) String() string {
	return fmt.Sprintf("%x", []byte(uuid))
}

func GetUUID(v interface{}) UUID {
	if v == nil {
		return UUID{}
	}

	if uuid, ok := v.(UUID); ok {
		return uuid
	}

	if bytes, ok := v.([]byte); ok {
		uuid := UUID{}

		for i, b := range bytes {
			uuid[i] = b
		}

		return uuid
	}

	if bytes, ok := v.([]uint8); ok {
		uuid := UUID{}

		for i, b := range bytes {
			uuid[i] = b
		}

		return uuid
	}

	log.Fatalf("invalid type for UUID: %#v", v)
	return UUID{}
}

var (
	CONNECTION_INVALID     = errors.New("connection invalid")
	CONNECTION_INTERRUPTED = errors.New("connection interrupted")
	CONNECTION_TERMINATED  = errors.New("connection terminated")

	TYPE_OF_UUID  = r.TypeOf(UUID{})
	TYPE_OF_BYTES = r.TypeOf([]byte{})
)

type XpcEventHandler interface {
	HandleXpcEvent(event Dict, err error)
}

func XpcConnect(service string, eh XpcEventHandler) XPC {
	cservice := C.CString(service)
	defer C.free(unsafe.Pointer(cservice))
	return XPC{conn: C.XpcConnect(cservice, unsafe.Pointer(&eh))}
}

//export handleXpcEvent
func handleXpcEvent(event C.xpc_object_t, p unsafe.Pointer) {
	//log.Printf("handleXpcEvent %#v %#v\n", event, p)

	t := C.xpc_get_type(event)
	eh := *((*XpcEventHandler)(p))

	if t == C.TYPE_ERROR {
		if event == C.ERROR_CONNECTION_INVALID {
			// The client process on the other end of the connection has either
			// crashed or cancelled the connection. After receiving this error,
			// the connection is in an invalid state, and you do not need to
			// call xpc_connection_cancel(). Just tear down any associated state
			// here.
			//log.Println("connection invalid")
			eh.HandleXpcEvent(nil, CONNECTION_INVALID)
		} else if event == C.ERROR_CONNECTION_INTERRUPTED {
			//log.Println("connection interrupted")
			eh.HandleXpcEvent(nil, CONNECTION_INTERRUPTED)
		} else if event == C.ERROR_CONNECTION_TERMINATED {
			// Handle per-connection termination cleanup.
			//log.Println("connection terminated")
			eh.HandleXpcEvent(nil, CONNECTION_TERMINATED)
		} else {
			//log.Println("got some error", event)
			eh.HandleXpcEvent(nil, fmt.Errorf("%v", event))
		}
	} else {
		eh.HandleXpcEvent(xpcToGo(event).(Dict), nil)
	}
}

// goToXpc converts a go object to an xpc object
func goToXpc(o interface{}) C.xpc_object_t {
	return valueToXpc(r.ValueOf(o))
}

// valueToXpc converts a go Value to an xpc object
//
// note that not all the types are supported, but only the subset required for Blued
func valueToXpc(val r.Value) C.xpc_object_t {
	if !val.IsValid() {
		return nil
	}

	var xv C.xpc_object_t

	switch val.Kind() {
	case r.Int, r.Int8, r.Int16, r.Int32, r.Int64:
		xv = C.xpc_int64_create(C.int64_t(val.Int()))

	case r.Uint, r.Uint8, r.Uint16, r.Uint32:
		xv = C.xpc_int64_create(C.int64_t(val.Uint()))

	case r.String:
		xv = C.xpc_string_create(C.CString(val.String()))

	case r.Map:
		xv = C.xpc_dictionary_create(nil, nil, 0)
		for _, k := range val.MapKeys() {
			v := valueToXpc(val.MapIndex(k))
			C.xpc_dictionary_set_value(xv, C.CString(k.String()), v)
			if v != nil {
				C.xpc_release(v)
			}
		}

	case r.Array, r.Slice:
		if val.Type() == TYPE_OF_UUID {
			// array of bytes
			var uuid [16]byte
			r.Copy(r.ValueOf(uuid[:]), val)
			xv = C.xpc_uuid_create(C.ptr_to_uuid(unsafe.Pointer(&uuid[0])))
		} else if val.Type() == TYPE_OF_BYTES {
			// slice of bytes
			xv = C.xpc_data_create(unsafe.Pointer(val.Pointer()), C.size_t(val.Len()))
		} else {
			xv = C.xpc_array_create(nil, 0)
			l := val.Len()

			for i := 0; i < l; i++ {
				v := valueToXpc(val.Index(i))
				C.xpc_array_append_value(xv, v)
				if v != nil {
					C.xpc_release(v)
				}
			}
		}

	case r.Interface, r.Ptr:
		xv = valueToXpc(val.Elem())

	default:
		log.Fatalf("unsupported %#v", val.String())
	}

	return xv
}

//export arraySet
func arraySet(u unsafe.Pointer, i C.int, v C.xpc_object_t) {
	a := *(*Array)(u)
	a[i] = xpcToGo(v)
}

//export dictSet
func dictSet(u unsafe.Pointer, k *C.char, v C.xpc_object_t) {
	d := *(*Dict)(u)
	d[C.GoString(k)] = xpcToGo(v)
}

// xpcToGo converts an xpc object to a go object
//
// note that not all the types are supported, but only the subset required for Blued
func xpcToGo(v C.xpc_object_t) interface{} {
	t := C.xpc_get_type(v)

	switch t {
	case C.TYPE_ARRAY:
		a := make(Array, C.int(C.xpc_array_get_count(v)))
		C.XpcArrayApply(unsafe.Pointer(&a), v)
		return a

	case C.TYPE_DATA:
		return C.GoBytes(C.xpc_data_get_bytes_ptr(v), C.int(C.xpc_data_get_length(v)))

	case C.TYPE_DICT:
		d := make(Dict)
		C.XpcDictApply(unsafe.Pointer(&d), v)
		return d

	case C.TYPE_INT64:
		return int64(C.xpc_int64_get_value(v))

	case C.TYPE_STRING:
		return C.GoString(C.xpc_string_get_string_ptr(v))

	case C.TYPE_UUID:
		a := [16]byte{}
		C.XpcUUIDGetBytes(unsafe.Pointer(&a), v)
		return UUID(a[:])

	default:
		log.Fatalf("unexpected type %#v, value %#v", t, v)
	}

	return nil
}

// xpc_release is needed by tests, since they can't use CGO
func xpc_release(xv C.xpc_object_t) {
	C.xpc_release(xv)
}

// this is used to check the OS version

type Utsname struct {
       Sysname  string
       Nodename string
       Release  string
       Version  string
       Machine  string
 }

func Uname(utsname *Utsname) error {
      var cstruct C.struct_utsname
      if err := C.uname(&cstruct); err != 0 {
              return errors.New("utsname error")
      }

      // XXX: this may crash if any value is exactly 256 characters (no 0 terminator)
      utsname.Sysname = C.GoString(&cstruct.sysname[0])
      utsname.Nodename = C.GoString(&cstruct.nodename[0])
      utsname.Release = C.GoString(&cstruct.release[0])
      utsname.Version = C.GoString(&cstruct.version[0])
      utsname.Machine = C.GoString(&cstruct.machine[0])

      return nil
}
<commit_msg>gofmt: xpc/xpc_darwin.go<commit_after>package xpc

/*
#include "xpc_wrapper_darwin.h"
#include "sys/utsname.h"
*/
import "C"

import (
	"errors"
	"fmt"
	"log"
	r "reflect"
	"unsafe"
)

type XPC struct {
	conn C.xpc_connection_t
}

func (x *XPC) Send(msg interface{}, verbose bool) {
	// verbose == true converts the type from bool to C._Bool
	C.XpcSendMessage(x.conn, goToXpc(msg), true, verbose == true)
}

//
// minimal XPC support required for BLE
//

// a dictionary of things
type Dict map[string]interface{}

func (d Dict) Contains(k string) bool {
	_, ok := d[k]
	return ok
}

func (d Dict) MustGetDict(k string) Dict {
	return d[k].(Dict)
}

func (d Dict) MustGetArray(k string) Array {
	return d[k].(Array)
}

func (d Dict) MustGetBytes(k string) []byte {
	return d[k].([]byte)
}

func (d Dict) MustGetHexBytes(k string) string {
	return fmt.Sprintf("%x", d[k].([]byte))
}

func (d Dict) MustGetInt(k string) int {
	return int(d[k].(int64))
}

func (d Dict) MustGetUUID(k string) []byte {
	u := d[k].(UUID)
	return u[:]
}

func (d Dict) GetString(k, defv string) string {
	if v := d[k]; v != nil {
		//log.Printf("GetString %s %#v\n", k, v)
		return v.(string)
	} else {
		//log.Printf("GetString %s default %#v\n", k, defv)
		return defv
	}
}

func (d Dict) GetBytes(k string, defv []byte) []byte {
	if v := d[k]; v != nil {
		//log.Printf("GetBytes %s %#v\n", k, v)
		return v.([]byte)
	} else {
		//log.Printf("GetBytes %s default %#v\n", k, defv)
		return defv
	}
}

func (d Dict) GetInt(k string, defv int) int {
	if v := d[k]; v != nil {
		//log.Printf("GetString %s %#v\n", k, v)
		return int(v.(int64))
	} else {
		//log.Printf("GetString %s default %#v\n", k, defv)
		return defv
	}
}

func (d Dict) GetUUID(k string) UUID {
	return GetUUID(d[k])
}

// an array of things
type Array []interface{}

func (a Array) GetUUID(k int) UUID {
	return GetUUID(a[k])
}

// a UUID
type UUID []byte

func MakeUUID(s string) UUID {
	var sl []byte
	fmt.Sscanf(s, "%32x", &sl)

	var uuid [16]byte
	copy(uuid[:], sl)
	return UUID(uuid[:])
}

func (uuid UUID) String() string {
	return fmt.Sprintf("%x", []byte(uuid))
}

func GetUUID(v interface{}) UUID {
	if v == nil {
		return UUID{}
	}

	if uuid, ok := v.(UUID); ok {
		return uuid
	}

	if bytes, ok := v.([]byte); ok {
		uuid := UUID{}

		for i, b := range bytes {
			uuid[i] = b
		}

		return uuid
	}

	if bytes, ok := v.([]uint8); ok {
		uuid := UUID{}

		for i, b := range bytes {
			uuid[i] = b
		}

		return uuid
	}

	log.Fatalf("invalid type for UUID: %#v", v)
	return UUID{}
}

var (
	CONNECTION_INVALID     = errors.New("connection invalid")
	CONNECTION_INTERRUPTED = errors.New("connection interrupted")
	CONNECTION_TERMINATED  = errors.New("connection terminated")

	TYPE_OF_UUID  = r.TypeOf(UUID{})
	TYPE_OF_BYTES = r.TypeOf([]byte{})
)

type XpcEventHandler interface {
	HandleXpcEvent(event Dict, err error)
}

func XpcConnect(service string, eh XpcEventHandler) XPC {
	cservice := C.CString(service)
	defer C.free(unsafe.Pointer(cservice))
	return XPC{conn: C.XpcConnect(cservice, unsafe.Pointer(&eh))}
}

//export handleXpcEvent
func handleXpcEvent(event C.xpc_object_t, p unsafe.Pointer) {
	//log.Printf("handleXpcEvent %#v %#v\n", event, p)

	t := C.xpc_get_type(event)
	eh := *((*XpcEventHandler)(p))

	if t == C.TYPE_ERROR {
		if event == C.ERROR_CONNECTION_INVALID {
			// The client process on the other end of the connection has either
			// crashed or cancelled the connection. After receiving this error,
			// the connection is in an invalid state, and you do not need to
			// call xpc_connection_cancel(). Just tear down any associated state
			// here.
			//log.Println("connection invalid")
			eh.HandleXpcEvent(nil, CONNECTION_INVALID)
		} else if event == C.ERROR_CONNECTION_INTERRUPTED {
			//log.Println("connection interrupted")
			eh.HandleXpcEvent(nil, CONNECTION_INTERRUPTED)
		} else if event == C.ERROR_CONNECTION_TERMINATED {
			// Handle per-connection termination cleanup.
			//log.Println("connection terminated")
			eh.HandleXpcEvent(nil, CONNECTION_TERMINATED)
		} else {
			//log.Println("got some error", event)
			eh.HandleXpcEvent(nil, fmt.Errorf("%v", event))
		}
	} else {
		eh.HandleXpcEvent(xpcToGo(event).(Dict), nil)
	}
}

// goToXpc converts a go object to an xpc object
func goToXpc(o interface{}) C.xpc_object_t {
	return valueToXpc(r.ValueOf(o))
}

// valueToXpc converts a go Value to an xpc object
//
// note that not all the types are supported, but only the subset required for Blued
func valueToXpc(val r.Value) C.xpc_object_t {
	if !val.IsValid() {
		return nil
	}

	var xv C.xpc_object_t

	switch val.Kind() {
	case r.Int, r.Int8, r.Int16, r.Int32, r.Int64:
		xv = C.xpc_int64_create(C.int64_t(val.Int()))

	case r.Uint, r.Uint8, r.Uint16, r.Uint32:
		xv = C.xpc_int64_create(C.int64_t(val.Uint()))

	case r.String:
		xv = C.xpc_string_create(C.CString(val.String()))

	case r.Map:
		xv = C.xpc_dictionary_create(nil, nil, 0)
		for _, k := range val.MapKeys() {
			v := valueToXpc(val.MapIndex(k))
			C.xpc_dictionary_set_value(xv, C.CString(k.String()), v)
			if v != nil {
				C.xpc_release(v)
			}
		}

	case r.Array, r.Slice:
		if val.Type() == TYPE_OF_UUID {
			// array of bytes
			var uuid [16]byte
			r.Copy(r.ValueOf(uuid[:]), val)
			xv = C.xpc_uuid_create(C.ptr_to_uuid(unsafe.Pointer(&uuid[0])))
		} else if val.Type() == TYPE_OF_BYTES {
			// slice of bytes
			xv = C.xpc_data_create(unsafe.Pointer(val.Pointer()), C.size_t(val.Len()))
		} else {
			xv = C.xpc_array_create(nil, 0)
			l := val.Len()

			for i := 0; i < l; i++ {
				v := valueToXpc(val.Index(i))
				C.xpc_array_append_value(xv, v)
				if v != nil {
					C.xpc_release(v)
				}
			}
		}

	case r.Interface, r.Ptr:
		xv = valueToXpc(val.Elem())

	default:
		log.Fatalf("unsupported %#v", val.String())
	}

	return xv
}

//export arraySet
func arraySet(u unsafe.Pointer, i C.int, v C.xpc_object_t) {
	a := *(*Array)(u)
	a[i] = xpcToGo(v)
}

//export dictSet
func dictSet(u unsafe.Pointer, k *C.char, v C.xpc_object_t) {
	d := *(*Dict)(u)
	d[C.GoString(k)] = xpcToGo(v)
}

// xpcToGo converts an xpc object to a go object
//
// note that not all the types are supported, but only the subset required for Blued
func xpcToGo(v C.xpc_object_t) interface{} {
	t := C.xpc_get_type(v)

	switch t {
	case C.TYPE_ARRAY:
		a := make(Array, C.int(C.xpc_array_get_count(v)))
		C.XpcArrayApply(unsafe.Pointer(&a), v)
		return a

	case C.TYPE_DATA:
		return C.GoBytes(C.xpc_data_get_bytes_ptr(v), C.int(C.xpc_data_get_length(v)))

	case C.TYPE_DICT:
		d := make(Dict)
		C.XpcDictApply(unsafe.Pointer(&d), v)
		return d

	case C.TYPE_INT64:
		return int64(C.xpc_int64_get_value(v))

	case C.TYPE_STRING:
		return C.GoString(C.xpc_string_get_string_ptr(v))

	case C.TYPE_UUID:
		a := [16]byte{}
		C.XpcUUIDGetBytes(unsafe.Pointer(&a), v)
		return UUID(a[:])

	default:
		log.Fatalf("unexpected type %#v, value %#v", t, v)
	}

	return nil
}

// xpc_release is needed by tests, since they can't use CGO
func xpc_release(xv C.xpc_object_t) {
	C.xpc_release(xv)
}

// this is used to check the OS version

type Utsname struct {
	Sysname  string
	Nodename string
	Release  string
	Version  string
	Machine  string
}

func Uname(utsname *Utsname) error {
	var cstruct C.struct_utsname
	if err := C.uname(&cstruct); err != 0 {
		return errors.New("utsname error")
	}

	// XXX: this may crash if any value is exactly 256 characters (no 0 terminator)
	utsname.Sysname = C.GoString(&cstruct.sysname[0])
	utsname.Nodename = C.GoString(&cstruct.nodename[0])
	utsname.Release = C.GoString(&cstruct.release[0])
	utsname.Version = C.GoString(&cstruct.version[0])
	utsname.Machine = C.GoString(&cstruct.machine[0])

	return nil
}
<|endoftext|>


<commit_before>package ultimate

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	_ "net/http/pprof"

	"github.com/hellodudu/comment/config"
)

var testChan chan interface{} = make(chan interface{}, 1)

type HttpServer struct {
}

func NewHttpServer() (*HttpServer, error) {
	return &HttpServer{}, nil
}

func (server *HttpServer) Run() {
	http.HandleFunc("/create_app", createAppHandler)
	http.HandleFunc("/task", taskHandler)
	http.HandleFunc("/ws", wsHandler)
	http.HandleFunc("/bn", binaryHandler)
	log.Fatal(http.ListenAndServe(config.HttpListenAddr, nil))
}

func taskHandler(w http.ResponseWriter, r *http.Request) {
	c := make(chan struct{}, 1)
	GetUltimateAPI().AddTask(func() {
		w.Write([]byte("taskHandler Callback!"))
		c <- struct{}{}
	})
	<-c
	log.Printf("taskHandler over\n", w)
}

func wsHandler(w http.ResponseWriter, r *http.Request) {
	conn, err := config.Upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
	}

	for {
		msgtype, p, err := conn.ReadMessage()
		if err != nil {
			log.Println(err)
			return
		}

		res := []byte("server recv:")
		if err := conn.WriteMessage(msgtype, append(res, p...)); err != nil {
			log.Println(err)
			return
		}
	}
}

func createAppHandler(w http.ResponseWriter, r *http.Request) {

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Fatal(err)
	}

	newApp := &App{}
	if err := json.Unmarshal(body, newApp); err != nil {
		log.Fatal(err)
	}

	// add app
	if err := GetUltimateAPI().AddNewApp(newApp); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	retBuf, retErr := json.Marshal(newApp)
	if retErr != nil {
		log.Fatal("create app response json marshal error!")
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(retBuf)
}

// for test
func binaryHandler(w http.ResponseWriter, r *http.Request) {
	data := []byte{58, 0, 0, 0, 94, 144, 225, 39, 10, 52, 10, 9, 104, 101, 108, 108, 111, 100, 117, 100, 117, 16, 161, 96, 26, 21, 104, 101, 108, 108, 111, 100, 117, 100, 117, 56, 54, 64, 103, 109, 97, 105, 108, 46, 99, 111, 109, 34, 13, 10, 11, 49, 51, 52, 48, 49, 48, 51, 57, 50, 57, 55}

	GetUltimateAPI().GetWorldSession().HandleMessage(nil, data)
}
<commit_msg>travis compile error<commit_after>package ultimate

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	_ "net/http/pprof"

	"github.com/hellodudu/comment/config"
)

var testChan chan interface{} = make(chan interface{}, 1)

type HttpServer struct {
}

func NewHttpServer() (*HttpServer, error) {
	return &HttpServer{}, nil
}

func (server *HttpServer) Run() {
	http.HandleFunc("/create_app", createAppHandler)
	http.HandleFunc("/task", taskHandler)
	http.HandleFunc("/ws", wsHandler)
	http.HandleFunc("/bn", binaryHandler)
	log.Fatal(http.ListenAndServe(config.HttpListenAddr, nil))
}

func taskHandler(w http.ResponseWriter, r *http.Request) {
	c := make(chan struct{}, 1)
	GetUltimateAPI().AddTask(func() {
		w.Write([]byte("taskHandler Callback!"))
		c <- struct{}{}
	})
	<-c
}

func wsHandler(w http.ResponseWriter, r *http.Request) {
	conn, err := config.Upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println(err)
	}

	for {
		msgtype, p, err := conn.ReadMessage()
		if err != nil {
			log.Println(err)
			return
		}

		res := []byte("server recv:")
		if err := conn.WriteMessage(msgtype, append(res, p...)); err != nil {
			log.Println(err)
			return
		}
	}
}

func createAppHandler(w http.ResponseWriter, r *http.Request) {

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		log.Fatal(err)
	}

	newApp := &App{}
	if err := json.Unmarshal(body, newApp); err != nil {
		log.Fatal(err)
	}

	// add app
	if err := GetUltimateAPI().AddNewApp(newApp); err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	retBuf, retErr := json.Marshal(newApp)
	if retErr != nil {
		log.Fatal("create app response json marshal error!")
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	w.Write(retBuf)
}

// for test
func binaryHandler(w http.ResponseWriter, r *http.Request) {
	data := []byte{58, 0, 0, 0, 94, 144, 225, 39, 10, 52, 10, 9, 104, 101, 108, 108, 111, 100, 117, 100, 117, 16, 161, 96, 26, 21, 104, 101, 108, 108, 111, 100, 117, 100, 117, 56, 54, 64, 103, 109, 97, 105, 108, 46, 99, 111, 109, 34, 13, 10, 11, 49, 51, 52, 48, 49, 48, 51, 57, 50, 57, 55}

	GetUltimateAPI().GetWorldSession().HandleMessage(nil, data)
}
<|endoftext|>