james-barrow / golang-ipc Goto Github PK
View Code? Open in Web Editor NEWGolang Inter-process communication library for Window, Mac and Linux.
License: MIT License
Golang Inter-process communication library for Window, Mac and Linux.
License: MIT License
I am trying to use this library to implement communications between a client running as a user and an elevated server running as root. e.g. I need to manipulate the network stack from a user app.
Everything works fine if both run as a user. But if the server runs as root, the socket file gets root permission and the client panics with a permission error.
Is there an undocumented way to have the socket created with write permission? For the moment, this is on Linux. But I am also hoping to use this on Windows and MacOS as well.
A race condition happens when opening a client
Here's the error
==================
WARNING: DATA RACE
Write at 0x00c000136140 by goroutine 7:
github.com/james-barrow/golang-ipc.startClient()
/Users/thomas/go/pkg/mod/github.com/james-barrow/[email protected]/client_all.go:63 +0x38
github.com/james-barrow/golang-ipc.StartClient.func1()
/Users/thomas/go/pkg/mod/github.com/james-barrow/[email protected]/client_all.go:56 +0x34
Previous read at 0x00c000136140 by main goroutine:
github.com/james-barrow/golang-ipc.(*Client).Write()
/Users/thomas/go/pkg/mod/github.com/james-barrow/[email protected]/client_all.go:198 +0x4c
main.startIPCClient()
/Users/thomas/go/src/github.com/equals215/deepsentinel/agent/test-tbd/main.go:18 +0x9c
main.main()
/Users/thomas/go/src/github.com/equals215/deepsentinel/agent/test-tbd/main.go:10 +0x20
Goroutine 7 (running) created at:
github.com/james-barrow/golang-ipc.StartClient()
/Users/thomas/go/pkg/mod/github.com/james-barrow/[email protected]/client_all.go:56 +0x388
main.startIPCClient()
/Users/thomas/go/src/github.com/equals215/deepsentinel/agent/test-tbd/main.go:14 +0x58
main.main()
/Users/thomas/go/src/github.com/equals215/deepsentinel/agent/test-tbd/main.go:10 +0x20
==================
Found 1 data race(s)
exit status 66
Here's the code that trigger this race condition :
package main
import (
"fmt"
ipc "github.com/james-barrow/golang-ipc"
)
func main() {
startIPCClient()
}
func startIPCClient() (*ipc.Client, error) {
c, err := ipc.StartClient("testIPC", &ipc.ClientConfig{Timeout: 500})
if err != nil {
return nil, err
}
c.Write(1, []byte("ping"))
resp, err := c.Read()
if err != nil {
return nil, err
}
if string(resp.Data) != "pong" {
return nil, fmt.Errorf("unexpected response: %s", resp.Data)
}
return c, nil
}
I tried the code snippets in the README file and it does not work. Performing writes from the client or server results in a "Not Connected" error while performing reads from the client server results in a "Connecting" error. So what triggers an actual connection? There is no exposed interface for this and no documentation.
from example, if i remove "time.Sleep(time.Second)" <-- basically make it send as fast as possible, receiver end will receive nothing.
why?
I noticed this using ProcessExplorer from Sysinternals on Windows, with this trivial program and v1.2.2:
func main() {
if len(os.Args) == 2 {
s, err := ipc.StartServer("sdtool_pipe", nil)
if err != nil {
fmt.Println(err)
return
}
for {
if msg, err := s.Read(); err != nil {
fmt.Println(err)
continue
} else {
fmt.Printf("CLIENT MSG: %+v\n", msg)
}
err = s.Write(1, []byte("PONG"))
if err == nil {
// handle error
fmt.Println(err)
}
}
} else {
c, err := ipc.StartClient("sdtool_pipe", nil)
if err != nil {
fmt.Println(err)
return
}
for i := 0; i < 10; i++ {
message, err := c.Read() // client
if err != nil {
fmt.Println(err)
continue
}
fmt.Printf("GOT MSG: %+v\n", message)
// do something with the received messages
err = c.Write(1, []byte("PING"))
if err != nil {
fmt.Println(err)
continue
}
}
}
}
Then, running app.exe serve
only starts the server side, and lists two separate \Device\NamedPipe\sdtool_pipe
entries in the open HANDLEs list of ProcessExplorer. I'm not sure why two, but that's not a big deal. Running app.exe
will spin up a client to connect, and that adds another reference to the pipe in the server (which persists after the client exits). Running the client again will add a 4th reference, etc.
I suspect the problem is the server accept loop unconditionally overwriting the old connection with the new one:
Line 70 in 71e822d
.Close()
first, then the open file count rises to 3 for the first client run, but stays there for the second and further client runs (and I can see on old entry being cleaned up and a new one being added):
if s.status == Listening || s.status == ReConnecting {
if s.conn != nil {
s.conn.Close()
}
s.conn = conn
I'm not sure if there's a way to get rid of the reference when the first client goes away, but wouldn't it be easier if the accept part was something the API user does, and that creates a separate object that manages each connection? That would seem to be the only way to handle multiple clients attempting to connect.
It looks like it broke in 71e822d with the refactor in types.go
:
$ go1.20.2.exe build
# github.com/james-barrow/golang-ipc
C:\Users\Matt\go\pkg\mod\github.com\james-barrow\[email protected]\connect_windows.go:28:4: s.connChannel undefined (type *Server has no field or method connChannel)
C:\Users\Matt\go\pkg\mod\github.com\james-barrow\[email protected]\connect_windows.go:32:12: s.connectionTimer undefined (type *Server has no field or method connectionTimer)
When running .Close()
on a server or client that has not yet connected, a nil-pointer panic is thrown, since the connection (that is being closed) has not yet been initialized.
Hello,
I have been implementing this in 2 go executables
server.go:
package main
import (
"fmt"
"log"
ipc "github.com/james-barrow/golang-ipc"
)
type PowerManagementCommand struct {
Command string
}
func main() {
sc, err := ipc.StartServer("echo", nil)
if err != nil {
log.Println(err)
return
}
for {
data, err := sc.Read()
if err == nil {
fmt.Print("Recieedede")
log.Println("Server recieved: "+string(data.Data)+" - Message type: ", data.MsgType)
} else {
log.Println(err)
break
}
}
}
client.go
package main
import (
"log"
ipc "github.com/james-barrow/golang-ipc"
)
func main() {
cc, err := ipc.StartClient("echo", nil)
if err != nil {
log.Println(err)
return
}
_ = cc.Write(5, []byte("Message from client"))
}
I confirm that a socket is created at /tmp/echo.sock, but everytime client.go is executed, nothing happens on server.go
Error returned from the client is:
Message exceeds maximum message length%
Is there something I'm missing?
Thanks in advance
This is not a bug, but idiomatic way to declare enumerated constant using iota.
https://go.dev/doc/effective_go#constants
`const (
// NotConnected - 0
NotConnected Status = iota
// Listening - 1
Listening
// Connecting - 2
Connecting
// Connected - 3
Connected
// ReConnecting - 4
ReConnecting
// Closed - 5
Closed
// Closing - 6
Closing
// Error - 7
Error
// Timeout - 8
Timeout
// Disconnected - 9
Disconnected
)`
i found the message type -1 is status change,so iwanna know if this can be used as heartbeat,or i nned implement th heartbeat myself?
If client sends message with size for 4000 bytes, server would receive part of them
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.