Skip to content

Instantly share code, notes, and snippets.

@tehmoon
Last active September 9, 2018 17:57
Show Gist options
  • Save tehmoon/8f40020b80906c43bb4488f465a7870f to your computer and use it in GitHub Desktop.
Save tehmoon/8f40020b80906c43bb4488f465a7870f to your computer and use it in GitHub Desktop.
Go stuff

This is specific to Alpine using the go apk.

Compiling go binaries in same arch:

go build -buildmode exe -ldflags '-linkmode external -extldflags "-static"' .

Compiling go binaries in other arch:

GOARCH=xxx go build -buildmode exe -ldflags '-linkmode internal -extldflags "-static"' .

It looks like Alpine[1] force -buildmode pie by default which doesn't work well for cross compile because of gcc:

--disable-multilib where gcc should include libs for arm64 and x86 families.

You can also pass -w -s to strip symbols from the binary.

A little word on linkmode[2][3]:

-linkmode mode
	Set link mode (internal, external, auto).
	This sets the linking mode as described in cmd/cgo/doc.go.

Sources:

package main
import (
"errors"
"runtime"
"time"
"log"
"os"
"os/signal"
"math/rand"
)
var threads = runtime.NumCPU()
func main() {
rand.Seed(time.Now().UnixNano())
if threads <= 0 {
// Set default value here
threads = runtime.NumCPU()
}
wait := make(chan struct{}, 0)
tracker := make(chan struct{}, threads - 1) // We sub 1 because channels starts at 0
sync := make(chan error, 0)
cancel := make(chan struct{}, 0) // Optional but nice to have
storage := make([]error, 0)
go func() {
var err error
for range tracker {
err = <- sync
if err != nil {
storage = append(storage, err)
// In case you want to cancel when receiving errors
// This will create temp goroutines
go func() {
log.Println("canceling due to error")
cancel <- struct{}{}
log.Println("cancelled")
}()
}
}
wait <- struct{}{}
}()
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)
go func() {
// Simulate cancel after 5 seconds
time.Sleep(5 * time.Second)
cancel <- struct{}{}
}()
LOOP: for i := 0; i < 100; i++ {
select {
// The cancel channel is optiona
case <- cancel:
log.Printf("Canceling received")
// Creating one last goroutine that will drain all other
// cancel requests
go func() {
for range cancel {
<- cancel
}
}()
break LOOP
// This is optional too if you don't care about signals
case <- c:
log.Printf("Sig int received")
break LOOP
default:
tracker <- struct{}{}
}
go func(i int) {
log.Printf("JobID: %d running\n", i)
time.Sleep(time.Millisecond * time.Duration(rand.Int31n(500)))
log.Printf("JobID: %d done\n", i)
if rand.Int31n(10) == 3 {
log.Printf("Error in JobID: %d\n", i)
sync <- errors.New("blah")
return
}
sync <- nil
}(i)
}
log.Println("Done scheduling, closing channel")
close(tracker)
log.Println("Channel closed, waiting for draining")
<- wait
log.Println("Restoring signal")
signal.Stop(c)
close(c)
log.Printf("%d errors found\n", len(storage))
time.Sleep(6 * time.Second)
}
package main
import (
"io"
"net"
"fmt"
"os"
)
// This will listen to a ip:port, each connection
// made to it will open a connection to the addr specified in arg
// and transfer the traffic.
// It can forward to remote ip:port and does ipv6 -> ipv4 out of the box.
var ADDR = ":12346" // CHANGE THIS
func main() {
if len(os.Args) != 2 {
fmt.Printf("%s <addr>\n", os.Args[0])
return
}
l, err := net.Listen("tcp", ADDR)
if err != nil {
panic(err)
}
for {
remote, err := l.Accept()
if err != nil {
continue
}
fmt.Println("new conn")
go func(remote net.Conn) {
local, err := net.Dial("tcp", os.Args[1])
if err != nil {
fmt.Println(err.Error())
return
}
fmt.Println("local opened")
sync := make(chan struct {}, 0)
go func() {
io.Copy(local, remote)
sync <- struct{}{}
}()
go func() {
io.Copy(remote, local)
sync <- struct{}{}
}()
fmt.Println("waiting")
<- sync
<- sync
fmt.Println("closing")
local.Close()
remote.Close()
}(remote)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment