github.com/metacubex/gvisor@v0.0.0-20240320004321-933faba989ec/pkg/eventchannel/event.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package eventchannel contains functionality for sending any protobuf message 16 // on a socketpair. 17 // 18 // The wire format is a uvarint length followed by a binary protobuf.Any 19 // message. 20 package eventchannel 21 22 import ( 23 "encoding/binary" 24 "fmt" 25 26 "google.golang.org/protobuf/encoding/prototext" 27 "google.golang.org/protobuf/proto" 28 "google.golang.org/protobuf/types/known/anypb" 29 "github.com/metacubex/gvisor/pkg/errors/linuxerr" 30 pb "github.com/metacubex/gvisor/pkg/eventchannel/eventchannel_go_proto" 31 "github.com/metacubex/gvisor/pkg/log" 32 "github.com/metacubex/gvisor/pkg/sync" 33 "github.com/metacubex/gvisor/pkg/unet" 34 ) 35 36 // Emitter emits a proto message. 37 type Emitter interface { 38 // Emit writes a single eventchannel message to an emitter. Emit should 39 // return hangup = true to indicate an emitter has "hung up" and no further 40 // messages should be directed to it. 41 Emit(msg proto.Message) (hangup bool, err error) 42 43 // Close closes this emitter. Emit cannot be used after Close is called. 44 Close() error 45 } 46 47 // DefaultEmitter is the default emitter. Calls to Emit and AddEmitter are sent 48 // to this Emitter. 49 var DefaultEmitter = &multiEmitter{} 50 51 // Emit is a helper method that calls DefaultEmitter.Emit. 52 func Emit(msg proto.Message) error { 53 _, err := DefaultEmitter.Emit(msg) 54 return err 55 } 56 57 // LogEmit is a helper method that calls DefaultEmitter.Emit. 58 // It also logs a warning message when an error occurs. 59 func LogEmit(msg proto.Message) error { 60 _, err := DefaultEmitter.Emit(msg) 61 if err != nil { 62 log.Warningf("unable to emit event: %s", err) 63 } 64 return err 65 } 66 67 // AddEmitter is a helper method that calls DefaultEmitter.AddEmitter. 68 func AddEmitter(e Emitter) { 69 DefaultEmitter.AddEmitter(e) 70 } 71 72 // HaveEmitters indicates if any emitters have been registered to the 73 // default emitter. 74 func HaveEmitters() bool { 75 DefaultEmitter.mu.Lock() 76 defer DefaultEmitter.mu.Unlock() 77 78 return len(DefaultEmitter.emitters) > 0 79 } 80 81 // multiEmitter is an Emitter that forwards messages to multiple Emitters. 82 type multiEmitter struct { 83 // mu protects emitters. 84 mu sync.Mutex 85 // emitters is initialized lazily in AddEmitter. 86 emitters map[Emitter]struct{} 87 } 88 89 // Emit emits a message using all added emitters. 90 func (me *multiEmitter) Emit(msg proto.Message) (bool, error) { 91 me.mu.Lock() 92 defer me.mu.Unlock() 93 94 var err error 95 for e := range me.emitters { 96 hangup, eerr := e.Emit(msg) 97 if eerr != nil { 98 if err == nil { 99 err = fmt.Errorf("error emitting %v: on %v: %v", msg, e, eerr) 100 } else { 101 err = fmt.Errorf("%v; on %v: %v", err, e, eerr) 102 } 103 104 // Log as well, since most callers ignore the error. 105 log.Warningf("Error emitting %v on %v: %v", msg, e, eerr) 106 } 107 if hangup { 108 log.Infof("Hangup on eventchannel emitter %v.", e) 109 delete(me.emitters, e) 110 } 111 } 112 113 return false, err 114 } 115 116 // AddEmitter adds a new emitter. 117 func (me *multiEmitter) AddEmitter(e Emitter) { 118 me.mu.Lock() 119 defer me.mu.Unlock() 120 if me.emitters == nil { 121 me.emitters = make(map[Emitter]struct{}) 122 } 123 me.emitters[e] = struct{}{} 124 } 125 126 // Close closes all emitters. If any Close call errors, it returns the first 127 // one encountered. 128 func (me *multiEmitter) Close() error { 129 me.mu.Lock() 130 defer me.mu.Unlock() 131 var err error 132 for e := range me.emitters { 133 if eerr := e.Close(); err == nil && eerr != nil { 134 err = eerr 135 } 136 delete(me.emitters, e) 137 } 138 return err 139 } 140 141 // socketEmitter emits proto messages on a socket. 142 type socketEmitter struct { 143 socket *unet.Socket 144 } 145 146 // SocketEmitter creates a new event channel based on the given fd. 147 // 148 // SocketEmitter takes ownership of fd. 149 func SocketEmitter(fd int) (Emitter, error) { 150 s, err := unet.NewSocket(fd) 151 if err != nil { 152 return nil, err 153 } 154 155 return &socketEmitter{ 156 socket: s, 157 }, nil 158 } 159 160 // Emit implements Emitter.Emit. 161 func (s *socketEmitter) Emit(msg proto.Message) (bool, error) { 162 any, err := anypb.New(msg) 163 if err != nil { 164 return false, err 165 } 166 bufMsg, err := proto.Marshal(any) 167 if err != nil { 168 return false, err 169 } 170 171 // Wire format is uvarint message length followed by binary proto. 172 p := make([]byte, binary.MaxVarintLen64) 173 n := binary.PutUvarint(p, uint64(len(bufMsg))) 174 p = append(p[:n], bufMsg...) 175 for done := 0; done < len(p); { 176 n, err := s.socket.Write(p[done:]) 177 if err != nil { 178 return linuxerr.Equals(linuxerr.EPIPE, err), err 179 } 180 done += n 181 } 182 183 return false, nil 184 } 185 186 // Close implements Emitter.Emit. 187 func (s *socketEmitter) Close() error { 188 return s.socket.Close() 189 } 190 191 // debugEmitter wraps an emitter to emit stringified event messages. This is 192 // useful for debugging -- when the messages are intended for humans. 193 type debugEmitter struct { 194 inner Emitter 195 } 196 197 // DebugEmitterFrom creates a new event channel emitter by wrapping an existing 198 // raw emitter. 199 func DebugEmitterFrom(inner Emitter) Emitter { 200 return &debugEmitter{ 201 inner: inner, 202 } 203 } 204 205 func (d *debugEmitter) Emit(msg proto.Message) (bool, error) { 206 text, err := prototext.Marshal(msg) 207 if err != nil { 208 return false, err 209 } 210 ev := &pb.DebugEvent{ 211 Name: string(msg.ProtoReflect().Descriptor().FullName()), 212 Text: string(text), 213 } 214 return d.inner.Emit(ev) 215 } 216 217 func (d *debugEmitter) Close() error { 218 return d.inner.Close() 219 }