blob: 93980521217d2e5965550a56375d96e284651837 [file]
// Copyright 2017 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
package rpctype
import (
"fmt"
"net"
"net/rpc"
"time"
"github.com/google/syzkaller/pkg/log"
)
type RPCServer struct {
ln net.Listener
s *rpc.Server
}
func NewRPCServer(addr string, receiver interface{}) (*RPCServer, error) {
ln, err := net.Listen("tcp", addr)
if err != nil {
return nil, fmt.Errorf("failed to listen on %v: %v", addr, err)
}
s := rpc.NewServer()
s.Register(receiver)
serv := &RPCServer{
ln: ln,
s: s,
}
return serv, nil
}
func (serv *RPCServer) Serve() {
for {
conn, err := serv.ln.Accept()
if err != nil {
log.Logf(0, "failed to accept an rpc connection: %v", err)
continue
}
conn.(*net.TCPConn).SetKeepAlive(true)
conn.(*net.TCPConn).SetKeepAlivePeriod(time.Minute)
go serv.s.ServeConn(conn)
}
}
func (serv *RPCServer) Addr() net.Addr {
return serv.ln.Addr()
}
type RPCClient struct {
conn net.Conn
c *rpc.Client
}
func NewRPCClient(addr string) (*RPCClient, error) {
conn, err := net.DialTimeout("tcp", addr, 60*time.Second)
if err != nil {
return nil, err
}
conn.(*net.TCPConn).SetKeepAlive(true)
conn.(*net.TCPConn).SetKeepAlivePeriod(time.Minute)
cli := &RPCClient{
conn: conn,
c: rpc.NewClient(conn),
}
return cli, nil
}
func (cli *RPCClient) Call(method string, args, reply interface{}) error {
cli.conn.SetDeadline(time.Now().Add(5 * 60 * time.Second))
err := cli.c.Call(method, args, reply)
cli.conn.SetDeadline(time.Time{})
return err
}
func (cli *RPCClient) Close() {
cli.c.Close()
}
func RPCCall(addr, method string, args, reply interface{}) error {
c, err := NewRPCClient(addr)
if err != nil {
return err
}
defer c.Close()
return c.Call(method, args, reply)
}