Cannot convert *tls.listener to *net.TCPListener on golang - ssl

I created a TLS server on GO.
func main() {
Log("Hello server!")
cert, err := tls.LoadX509KeyPair("cert.pem", "key.pem")
if err != nil {
Log("server: loadkeys: ", err);
return;
}
config := tls.Config{Certificates: []tls.Certificate{cert}}
config.Rand = rand.Reader
service := "0.0.0.0:9988"
listener, err := tls.Listen("tcp", service, &config)
if err != nil {
Log("server: listen: %s", err)
return
}
defer listener.Close()
for {
Log("Waiting for clients")
connection, error := listener.Accept()
if error != nil {
Log("Client error: ", error)
} else {
//connection.SetLinger(0) //error here
go ClientHandler(connection)
}
}
}
I cannot call SetLinger function, because tls.Listen function returns net.Listener. I need net.TCPListener.
I tried:
tpcListener := listener.(*net.TCPListener)
Error: panic: interface conversion: net.Listener is *tls.listener, not *net.TCPListener
There is ListenTCP on net package but there is not ListenTCP on tls package.

You explicitly mention SetLinger but that's called on a TCPConn not on a TCPListener. Have you checked if the accepted net.Conn can be asserted to *net.TCPConn?
The crypto/tls package implements the net.Listener interface via a non-exported type so you cannot access the "inner" listener that way.
If you really need a net.TCPListener:
As with all the other Go standard packages that provide convenience functions that create listeners for you, there are lower level functions that let you create your own. So call net.ListenTCP, then whatever methods you like on it, then pass that to the tls package via tls.NewListener.
See the source for crypto/tls's Listen for further guidance.

Related

go-libp2p pubsub example not working in multithreaded environment

I am a beginner and am currently playing with the pubsub example from libp2p given here https://github.com/libp2p/go-libp2p/tree/master/examples/pubsub/basic-chat-with-rendezvous
I have been able to build the code and run the binary in different terminals and it works.
I am trying to automate this process from the main.go program itself where I can create a few threads to spin up new agents where they
publish messages to the network and the rest of the peers subscribe to it.
I have provided the modified code I have built currently but it doesnt seem to work. The peers cannot discover each other.
func main() {
help := flag.Bool("help", false, "Display Help")
cfg := parseFlags()
if *help {
fmt.Printf("Simple example for peer discovery using mDNS. mDNS is great when you have multiple peers in local LAN.")
fmt.Printf("Usage: \n Run './chat-with-mdns'\nor Run './chat-with-mdns -host [host] -port [port] -rendezvous [string] -pid [proto ID]'\n")
os.Exit(0)
}
fmt.Printf("[*] Listening on: %s with port: %d\n", cfg.listenHost, cfg.listenPort)
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
// Spawn a thread for each iteration in the loop.
// Pass 'i' into the goroutine's function
// in order to make sure each goroutine
// uses a different value for 'i'.
wg.Add(5)
go func(i int) {
// At the end of the goroutine, tell the WaitGroup
// that another thread has completed.
defer wg.Done()
ctx := context.Background()
r := rand.Reader
// Creates a new RSA key pair for this host.
prvKey, _, err := crypto.GenerateKeyPairWithReader(crypto.RSA, 2048, r)
if err != nil {
panic(err)
}
// 0.0.0.0 will listen on any interface device.
sourceMultiAddr, _ := multiaddr.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", cfg.listenHost, cfg.listenPort))
// libp2p.New constructs a new libp2p Host.
// Other options can be added here.
host, err := libp2p.New(
libp2p.ListenAddrs(sourceMultiAddr),
libp2p.Identity(prvKey),
)
if err != nil {
panic(err)
}
// Set a function as stream handler.
// This function is called when a peer initiates a connection and starts a stream with this peer.
host.SetStreamHandler(protocol.ID(cfg.ProtocolID), handleStream)
fmt.Printf("\n[*] Your Multiaddress Is: /ip4/%s/tcp/%v/p2p/%s\n", cfg.listenHost, cfg.listenPort, host.ID().Pretty())
peerChan := initMDNS(host, cfg.RendezvousString)
for { // allows multiple peers to join
peer := <-peerChan // will block untill we discover a peer // the code currently hangs here
fmt.Println("Found peer:", peer, ", connecting")
if err := host.Connect(ctx, peer); err != nil {
fmt.Println("Connection failed:", err)
continue
}
//** this part of the code is experimental and is not accessed by any thread yet **//
stream, err := host.NewStream(ctx, peer.ID, protocol.ID(cfg.ProtocolID))
if err != nil {
fmt.Println("Stream open failed", err)
} else {
rw := bufio.NewReadWriter(bufio.NewReader(stream), bufio.NewWriter(stream))
go writeData(rw)
go readData(rw)
fmt.Println("Connected to:", peer)
}
//** this part of the code is experimental and is not accessed by any thread yet **//
}
}(i)
}
fmt.Println("exit")
wg.Wait()
fmt.Println("Finished for loop")
}
But this doesn't seem to work. Are there any examples I can look at currently for solving this error.

sql golang invalid memory address or nil pointer dereference when do query

i am trying to insert data after the connection, when i command the logic of INSERT... i was able to connect to the database, but when i uncommand them , i got error
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x40f8e2a]
here is my function :
func Connect() (*sql.DB, error) {
db, err := sql.Open("postgres", os.Getenv("PG_URL"))
if err != nil {
return nil, err
}
defer db.Close()
stmt, _ := db.Prepare("INSERT INTO users(name, email, password) VALUES(?,?,?)")
res, err := stmt.Exec("test", "test#mail.com", "12344")
if err != nil{
panic(err.Error())
}
fmt.Println(res)
fmt.Println("Successfully connected!")
return db, nil
}
I have tried to do the same thing also like this article go sql
and have the same issue
do I wrong implement this?
I bet a dollar/euro/frank that the NPE is on the line executing the prepared statement and that if you check the only error you ignored it won't be nil and it will tell you what's wrong.
I had the same problem with sqlite.
As Ivaylo Novakov described in his answer I had to log the err of the prepare statement (which i ignored like you before stmt, _)
For me it was running okay as long as i was developing but when I created my final binary i forgot to enable cgo).
The err got the hint:
Binary was compiled with 'CGO_ENABLED=0', go-sqlite3 requires cgo to work. This is a stub

How to check a log/output in go test?

I have this function that logs the error in some cases:
func readByte(/*...*/){
// ...
if err != nil {
fmt.Println("ERROR")
log.Print("Couldn't read first byte")
return
}
// ...
}
Now, in the test file, I want to check the output error from this function:
c.Assert(OUTPUT, check.Matches, "teste")
How can I access the log? I tried to put a buffer but it didn't work. What is the right way to catch this log without change my readByte function code?
For example,
readbyte_test.go:
package main
import (
"bytes"
"fmt"
"io"
"log"
"os"
"testing"
)
func readByte( /*...*/ ) {
// ...
err := io.EOF // force an error
if err != nil {
fmt.Println("ERROR")
log.Print("Couldn't read first byte")
return
}
// ...
}
func TestReadByte(t *testing.T) {
var buf bytes.Buffer
log.SetOutput(&buf)
defer func() {
log.SetOutput(os.Stderr)
}()
readByte()
t.Log(buf.String())
}
Output:
$ go test -v readbyte_test.go
=== RUN TestReadByte
ERROR
--- PASS: TestReadByte (0.00s)
readbyte_test.go:30: 2017/05/22 16:41:00 Couldn't read first byte
PASS
ok command-line-arguments 0.004s
$
Answer for Concurrent Tests
If your test is running concurrently (for example, when testing an http Server or Client), you may encounter a race between writing to the buffer and reading from it. Instead of the buffer, we can redirect output to an os.Pipe and use a bufio.Scanner to block until output has been written by using the Scan() method.
Here is an example of creating an os.Pipe and setting the stdlib log package to use the pipe. Note my use of the testify/assert package here:
func mockLogger(t *testing.T) (*bufio.Scanner, *os.File, *os.File) {
reader, writer, err := os.Pipe()
if err != nil {
assert.Fail(t, "couldn't get os Pipe: %v", err)
}
log.SetOutput(writer)
return bufio.NewScanner(reader), reader, writer
}
The *os.File objects are returned so they can be properly closed with a deferred function. Here I'm just printing to stdout since if there was some strange error on close I personally wouldn't want to fail the test. However, this could easily be another call to t.Errorf or similar if you wanted:
func resetLogger(reader *os.File, writer *os.File) {
err := reader.Close()
if err != nil {
fmt.Println("error closing reader was ", err)
}
if err = writer.Close(); err != nil {
fmt.Println("error closing writer was ", err)
}
log.SetOutput(os.Stderr)
}
And then in your test you would have this pattern:
scanner, reader, writer := mockLogger(t) // turn this off when debugging or developing as you will miss output!
defer resetLogger(reader, writer)
// other setup as needed, getting some value for thing below
go concurrentAction()
scanner.Scan() // blocks until a new line is written to the pipe
got := scanner.Text() // the last line written to the scanner
msg := fmt.Sprintf("your log message with thing %v you care about", thing)
assert.Contains(t, got, msg)
And finally, the concurrentAction() function is calling a log function (or method if using a log.logger, the package actually behaves the same way with log.SetOutput() call above either way) like:
// doing something, getting value for thing
log.Printf("your log message with the thing %v you care about", thing)

Effect of duplicate Redis subscription to same channel name

To subscribe to an instance of StackExchange.Redis.ISubscriber one needs to call the following API:
void Subscribe(RedisChannel channel, Action<RedisChannel, RedisValue> handler, CommandFlags flags = CommandFlags.None);
Question is, what happens if one calls this same line of code with the same channel name as a simple string, say "TestChannel"?
Does ISubscriber check for string equality or it just does not care and therefore we will have two subscriptions?
I am making an assumption that your question is targeted at the Redis API itself. Please let me know if it isn't.
The answer is also based on the assumption that you are using a single redis client connection.
The pubsub map is a hashtable.
To answer your question: If you subscribe multiple times with the same string, you will continue to have only one subscription(you can see that the subscribe happens based on the hashtable here: https://github.com/antirez/redis/blob/3.2.6/src/pubsub.c#L64.
Conversely, calling a single unsubscribe will unsubscribe your other subscriptions for that channel/pattern as well.
If it helps, here is a simple example in Go (I have used the go-redis library) that illustrates the unsubscribe and hashtable storage parts of the answer.
package main
import (
"fmt"
"log"
"time"
"github.com/go-redis/redis"
)
func main() {
cl := redis.NewClient((&redis.Options{
Addr: "127.0.0.1:6379",
PoolSize: 1,
}))
ps := cl.Subscribe()
err := ps.Subscribe("testchannel")
if err != nil {
log.Fatal(err)
}
err = ps.Subscribe("testchannel")
if err != nil {
log.Fatal(err)
}
err = ps.Unsubscribe("testchannel")
if err != nil {
log.Fatal(err)
}
go func() {
msg, err := ps.ReceiveMessage()
if err != nil {
log.Fatal(err)
}
fmt.Println(msg.Payload)
}()
err = cl.Publish("testchannel", "some value").Err()
if err != nil {
log.Fatal(err)
}
time.Sleep(10 * time.Second)
}
A channel may have multiple subscribers. All client who subscribe to the same channel will receive the messages published on this given channel.

golang upload file err runtime error index out of range

I've put together a golang func that takes an uploaded file and saves it to folder.
Just before os.Create() I am getting the following error :
http: panic serving [::1]:64373: runtime error: index out of range
My golang function is:
func webUploadHandler(w http.ResponseWriter, r *http.Request) {
file, header, err := r.FormFile("file") // the FormFile function takes in the POST input id file
if err != nil {
fmt.Fprintln(w, err)
return
}
defer file.Close()
// My error comes here
messageId := r.URL.Query()["id"][0]
out, err := os.Create("./upload/" + messageId + ".mp3")
if err != nil {
fmt.Fprintf(w, "Unable to create the file for writing. Check your write access privilege")
return
}
defer out.Close()
// write the content from POST to the file
_, err = io.Copy(out, file)
if err != nil {
fmt.Fprintln(w, err)
}
fmt.Fprintf(w,"File uploaded successfully : ")
fmt.Fprintf(w, header.Filename)
}
any ideas? much appreciate
You should at least check if r.URL.Query()["id"] has actually one element.
If len(r.URL.Query()["id"]), you could consider not accessing the index 0.
Easier, Ainar-G suggests in the comments to use the Get() method
Get gets the first value associated with the given key.
If there are no values associated with the key, Get returns the empty string.
To access multiple values, use the map directly.