github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/rpc/comms/ipc_windows.go (about) 1 // Copyright 2015 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 // +build windows 18 19 package comms 20 21 import ( 22 "fmt" 23 "io" 24 "net" 25 "os" 26 "sync" 27 "syscall" 28 "time" 29 "unsafe" 30 31 "github.com/ethereum/go-ethereum/logger" 32 "github.com/ethereum/go-ethereum/logger/glog" 33 "github.com/ethereum/go-ethereum/rpc/codec" 34 "github.com/ethereum/go-ethereum/rpc/shared" 35 "github.com/ethereum/go-ethereum/rpc/useragent" 36 ) 37 38 var ( 39 modkernel32 = syscall.NewLazyDLL("kernel32.dll") 40 41 procCreateNamedPipeW = modkernel32.NewProc("CreateNamedPipeW") 42 procConnectNamedPipe = modkernel32.NewProc("ConnectNamedPipe") 43 procDisconnectNamedPipe = modkernel32.NewProc("DisconnectNamedPipe") 44 procWaitNamedPipeW = modkernel32.NewProc("WaitNamedPipeW") 45 procCreateEventW = modkernel32.NewProc("CreateEventW") 46 procGetOverlappedResult = modkernel32.NewProc("GetOverlappedResult") 47 procCancelIoEx = modkernel32.NewProc("CancelIoEx") 48 ) 49 50 func createNamedPipe(name *uint16, openMode uint32, pipeMode uint32, maxInstances uint32, outBufSize uint32, inBufSize uint32, defaultTimeout uint32, sa *syscall.SecurityAttributes) (handle syscall.Handle, err error) { 51 r0, _, e1 := syscall.Syscall9(procCreateNamedPipeW.Addr(), 8, uintptr(unsafe.Pointer(name)), uintptr(openMode), uintptr(pipeMode), uintptr(maxInstances), uintptr(outBufSize), uintptr(inBufSize), uintptr(defaultTimeout), uintptr(unsafe.Pointer(sa)), 0) 52 handle = syscall.Handle(r0) 53 if handle == syscall.InvalidHandle { 54 if e1 != 0 { 55 err = error(e1) 56 } else { 57 err = syscall.EINVAL 58 } 59 } 60 return 61 } 62 63 func cancelIoEx(handle syscall.Handle, overlapped *syscall.Overlapped) (err error) { 64 r1, _, e1 := syscall.Syscall(procCancelIoEx.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(overlapped)), 0) 65 if r1 == 0 { 66 if e1 != 0 { 67 err = error(e1) 68 } else { 69 err = syscall.EINVAL 70 } 71 } 72 return 73 } 74 75 func connectNamedPipe(handle syscall.Handle, overlapped *syscall.Overlapped) (err error) { 76 r1, _, e1 := syscall.Syscall(procConnectNamedPipe.Addr(), 2, uintptr(handle), uintptr(unsafe.Pointer(overlapped)), 0) 77 if r1 == 0 { 78 if e1 != 0 { 79 err = error(e1) 80 } else { 81 err = syscall.EINVAL 82 } 83 } 84 return 85 } 86 87 func disconnectNamedPipe(handle syscall.Handle) (err error) { 88 r1, _, e1 := syscall.Syscall(procDisconnectNamedPipe.Addr(), 1, uintptr(handle), 0, 0) 89 if r1 == 0 { 90 if e1 != 0 { 91 err = error(e1) 92 } else { 93 err = syscall.EINVAL 94 } 95 } 96 return 97 } 98 99 func waitNamedPipe(name *uint16, timeout uint32) (err error) { 100 r1, _, e1 := syscall.Syscall(procWaitNamedPipeW.Addr(), 2, uintptr(unsafe.Pointer(name)), uintptr(timeout), 0) 101 if r1 == 0 { 102 if e1 != 0 { 103 err = error(e1) 104 } else { 105 err = syscall.EINVAL 106 } 107 } 108 return 109 } 110 111 func createEvent(sa *syscall.SecurityAttributes, manualReset bool, initialState bool, name *uint16) (handle syscall.Handle, err error) { 112 var _p0 uint32 113 if manualReset { 114 _p0 = 1 115 } else { 116 _p0 = 0 117 } 118 var _p1 uint32 119 if initialState { 120 _p1 = 1 121 } else { 122 _p1 = 0 123 } 124 r0, _, e1 := syscall.Syscall6(procCreateEventW.Addr(), 4, uintptr(unsafe.Pointer(sa)), uintptr(_p0), uintptr(_p1), uintptr(unsafe.Pointer(name)), 0, 0) 125 handle = syscall.Handle(r0) 126 if handle == syscall.InvalidHandle { 127 if e1 != 0 { 128 err = error(e1) 129 } else { 130 err = syscall.EINVAL 131 } 132 } 133 return 134 } 135 136 func getOverlappedResult(handle syscall.Handle, overlapped *syscall.Overlapped, transferred *uint32, wait bool) (err error) { 137 var _p0 uint32 138 if wait { 139 _p0 = 1 140 } else { 141 _p0 = 0 142 } 143 r1, _, e1 := syscall.Syscall6(procGetOverlappedResult.Addr(), 4, uintptr(handle), uintptr(unsafe.Pointer(overlapped)), uintptr(unsafe.Pointer(transferred)), uintptr(_p0), 0, 0) 144 if r1 == 0 { 145 if e1 != 0 { 146 err = error(e1) 147 } else { 148 err = syscall.EINVAL 149 } 150 } 151 return 152 } 153 154 const ( 155 // openMode 156 pipe_access_duplex = 0x3 157 pipe_access_inbound = 0x1 158 pipe_access_outbound = 0x2 159 160 // openMode write flags 161 file_flag_first_pipe_instance = 0x00080000 162 file_flag_write_through = 0x80000000 163 file_flag_overlapped = 0x40000000 164 165 // openMode ACL flags 166 write_dac = 0x00040000 167 write_owner = 0x00080000 168 access_system_security = 0x01000000 169 170 // pipeMode 171 pipe_type_byte = 0x0 172 pipe_type_message = 0x4 173 174 // pipeMode read mode flags 175 pipe_readmode_byte = 0x0 176 pipe_readmode_message = 0x2 177 178 // pipeMode wait mode flags 179 pipe_wait = 0x0 180 pipe_nowait = 0x1 181 182 // pipeMode remote-client mode flags 183 pipe_accept_remote_clients = 0x0 184 pipe_reject_remote_clients = 0x8 185 186 pipe_unlimited_instances = 255 187 188 nmpwait_wait_forever = 0xFFFFFFFF 189 190 // the two not-an-errors below occur if a client connects to the pipe between 191 // the server's CreateNamedPipe and ConnectNamedPipe calls. 192 error_no_data syscall.Errno = 0xE8 193 error_pipe_connected syscall.Errno = 0x217 194 error_pipe_busy syscall.Errno = 0xE7 195 error_sem_timeout syscall.Errno = 0x79 196 197 error_bad_pathname syscall.Errno = 0xA1 198 error_invalid_name syscall.Errno = 0x7B 199 200 error_io_incomplete syscall.Errno = 0x3e4 201 ) 202 203 var _ net.Conn = (*PipeConn)(nil) 204 var _ net.Listener = (*PipeListener)(nil) 205 206 // ErrClosed is the error returned by PipeListener.Accept when Close is called 207 // on the PipeListener. 208 var ErrClosed = PipeError{"Pipe has been closed.", false} 209 210 // PipeError is an error related to a call to a pipe 211 type PipeError struct { 212 msg string 213 timeout bool 214 } 215 216 // Error implements the error interface 217 func (e PipeError) Error() string { 218 return e.msg 219 } 220 221 // Timeout implements net.AddrError.Timeout() 222 func (e PipeError) Timeout() bool { 223 return e.timeout 224 } 225 226 // Temporary implements net.AddrError.Temporary() 227 func (e PipeError) Temporary() bool { 228 return false 229 } 230 231 // Dial connects to a named pipe with the given address. If the specified pipe is not available, 232 // it will wait indefinitely for the pipe to become available. 233 // 234 // The address must be of the form \\.\\pipe\<name> for local pipes and \\<computer>\pipe\<name> 235 // for remote pipes. 236 // 237 // Dial will return a PipeError if you pass in a badly formatted pipe name. 238 // 239 // Examples: 240 // // local pipe 241 // conn, err := Dial(`\\.\pipe\mypipename`) 242 // 243 // // remote pipe 244 // conn, err := Dial(`\\othercomp\pipe\mypipename`) 245 func Dial(address string) (*PipeConn, error) { 246 for { 247 conn, err := dial(address, nmpwait_wait_forever) 248 if err == nil { 249 return conn, nil 250 } 251 if isPipeNotReady(err) { 252 <-time.After(100 * time.Millisecond) 253 continue 254 } 255 return nil, err 256 } 257 } 258 259 // DialTimeout acts like Dial, but will time out after the duration of timeout 260 func DialTimeout(address string, timeout time.Duration) (*PipeConn, error) { 261 deadline := time.Now().Add(timeout) 262 263 now := time.Now() 264 for now.Before(deadline) { 265 millis := uint32(deadline.Sub(now) / time.Millisecond) 266 conn, err := dial(address, millis) 267 if err == nil { 268 return conn, nil 269 } 270 if err == error_sem_timeout { 271 // This is WaitNamedPipe's timeout error, so we know we're done 272 return nil, PipeError{fmt.Sprintf( 273 "Timed out waiting for pipe '%s' to come available", address), true} 274 } 275 if isPipeNotReady(err) { 276 left := deadline.Sub(time.Now()) 277 retry := 100 * time.Millisecond 278 if left > retry { 279 <-time.After(retry) 280 } else { 281 <-time.After(left - time.Millisecond) 282 } 283 now = time.Now() 284 continue 285 } 286 return nil, err 287 } 288 return nil, PipeError{fmt.Sprintf( 289 "Timed out waiting for pipe '%s' to come available", address), true} 290 } 291 292 // isPipeNotReady checks the error to see if it indicates the pipe is not ready 293 func isPipeNotReady(err error) bool { 294 // Pipe Busy means another client just grabbed the open pipe end, 295 // and the server hasn't made a new one yet. 296 // File Not Found means the server hasn't created the pipe yet. 297 // Neither is a fatal error. 298 299 return err == syscall.ERROR_FILE_NOT_FOUND || err == error_pipe_busy 300 } 301 302 // newOverlapped creates a structure used to track asynchronous 303 // I/O requests that have been issued. 304 func newOverlapped() (*syscall.Overlapped, error) { 305 event, err := createEvent(nil, true, true, nil) 306 if err != nil { 307 return nil, err 308 } 309 return &syscall.Overlapped{HEvent: event}, nil 310 } 311 312 // waitForCompletion waits for an asynchronous I/O request referred to by overlapped to complete. 313 // This function returns the number of bytes transferred by the operation and an error code if 314 // applicable (nil otherwise). 315 func waitForCompletion(handle syscall.Handle, overlapped *syscall.Overlapped) (uint32, error) { 316 _, err := syscall.WaitForSingleObject(overlapped.HEvent, syscall.INFINITE) 317 if err != nil { 318 return 0, err 319 } 320 var transferred uint32 321 err = getOverlappedResult(handle, overlapped, &transferred, true) 322 return transferred, err 323 } 324 325 // dial is a helper to initiate a connection to a named pipe that has been started by a server. 326 // The timeout is only enforced if the pipe server has already created the pipe, otherwise 327 // this function will return immediately. 328 func dial(address string, timeout uint32) (*PipeConn, error) { 329 name, err := syscall.UTF16PtrFromString(string(address)) 330 if err != nil { 331 return nil, err 332 } 333 // If at least one instance of the pipe has been created, this function 334 // will wait timeout milliseconds for it to become available. 335 // It will return immediately regardless of timeout, if no instances 336 // of the named pipe have been created yet. 337 // If this returns with no error, there is a pipe available. 338 if err := waitNamedPipe(name, timeout); err != nil { 339 if err == error_bad_pathname { 340 // badly formatted pipe name 341 return nil, badAddr(address) 342 } 343 return nil, err 344 } 345 pathp, err := syscall.UTF16PtrFromString(address) 346 if err != nil { 347 return nil, err 348 } 349 handle, err := syscall.CreateFile(pathp, syscall.GENERIC_READ|syscall.GENERIC_WRITE, 350 uint32(syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE), nil, syscall.OPEN_EXISTING, 351 syscall.FILE_FLAG_OVERLAPPED, 0) 352 if err != nil { 353 return nil, err 354 } 355 return &PipeConn{handle: handle, addr: PipeAddr(address)}, nil 356 } 357 358 // Listen returns a new PipeListener that will listen on a pipe with the given 359 // address. The address must be of the form \\.\pipe\<name> 360 // 361 // Listen will return a PipeError for an incorrectly formatted pipe name. 362 func Listen(address string) (*PipeListener, error) { 363 handle, err := createPipe(address, true) 364 if err == error_invalid_name { 365 return nil, badAddr(address) 366 } 367 if err != nil { 368 return nil, err 369 } 370 return &PipeListener{ 371 addr: PipeAddr(address), 372 handle: handle, 373 }, nil 374 } 375 376 // PipeListener is a named pipe listener. Clients should typically 377 // use variables of type net.Listener instead of assuming named pipe. 378 type PipeListener struct { 379 addr PipeAddr 380 handle syscall.Handle 381 closed bool 382 383 // acceptHandle contains the current handle waiting for 384 // an incoming connection or nil. 385 acceptHandle syscall.Handle 386 // acceptOverlapped is set before waiting on a connection. 387 // If not waiting, it is nil. 388 acceptOverlapped *syscall.Overlapped 389 // acceptMutex protects the handle and overlapped structure. 390 acceptMutex sync.Mutex 391 } 392 393 // Accept implements the Accept method in the net.Listener interface; it 394 // waits for the next call and returns a generic net.Conn. 395 func (l *PipeListener) Accept() (net.Conn, error) { 396 c, err := l.AcceptPipe() 397 for err == error_no_data { 398 // Ignore clients that connect and immediately disconnect. 399 c, err = l.AcceptPipe() 400 } 401 if err != nil { 402 return nil, err 403 } 404 return c, nil 405 } 406 407 // AcceptPipe accepts the next incoming call and returns the new connection. 408 // It might return an error if a client connected and immediately cancelled 409 // the connection. 410 func (l *PipeListener) AcceptPipe() (*PipeConn, error) { 411 if l == nil || l.addr == "" || l.closed { 412 return nil, syscall.EINVAL 413 } 414 415 // the first time we call accept, the handle will have been created by the Listen 416 // call. This is to prevent race conditions where the client thinks the server 417 // isn't listening because it hasn't actually called create yet. After the first time, we'll 418 // have to create a new handle each time 419 handle := l.handle 420 if handle == 0 { 421 var err error 422 handle, err = createPipe(string(l.addr), false) 423 if err != nil { 424 return nil, err 425 } 426 } else { 427 l.handle = 0 428 } 429 430 overlapped, err := newOverlapped() 431 if err != nil { 432 return nil, err 433 } 434 defer syscall.CloseHandle(overlapped.HEvent) 435 if err := connectNamedPipe(handle, overlapped); err != nil && err != error_pipe_connected { 436 if err == error_io_incomplete || err == syscall.ERROR_IO_PENDING { 437 l.acceptMutex.Lock() 438 l.acceptOverlapped = overlapped 439 l.acceptHandle = handle 440 l.acceptMutex.Unlock() 441 defer func() { 442 l.acceptMutex.Lock() 443 l.acceptOverlapped = nil 444 l.acceptHandle = 0 445 l.acceptMutex.Unlock() 446 }() 447 448 _, err = waitForCompletion(handle, overlapped) 449 } 450 if err == syscall.ERROR_OPERATION_ABORTED { 451 // Return error compatible to net.Listener.Accept() in case the 452 // listener was closed. 453 return nil, ErrClosed 454 } 455 if err != nil { 456 return nil, err 457 } 458 } 459 return &PipeConn{handle: handle, addr: l.addr}, nil 460 } 461 462 // Close stops listening on the address. 463 // Already Accepted connections are not closed. 464 func (l *PipeListener) Close() error { 465 if l.closed { 466 return nil 467 } 468 l.closed = true 469 if l.handle != 0 { 470 err := disconnectNamedPipe(l.handle) 471 if err != nil { 472 return err 473 } 474 err = syscall.CloseHandle(l.handle) 475 if err != nil { 476 return err 477 } 478 l.handle = 0 479 } 480 l.acceptMutex.Lock() 481 defer l.acceptMutex.Unlock() 482 if l.acceptOverlapped != nil && l.acceptHandle != 0 { 483 // Cancel the pending IO. This call does not block, so it is safe 484 // to hold onto the mutex above. 485 if err := cancelIoEx(l.acceptHandle, l.acceptOverlapped); err != nil { 486 return err 487 } 488 err := syscall.CloseHandle(l.acceptOverlapped.HEvent) 489 if err != nil { 490 return err 491 } 492 l.acceptOverlapped.HEvent = 0 493 err = syscall.CloseHandle(l.acceptHandle) 494 if err != nil { 495 return err 496 } 497 l.acceptHandle = 0 498 } 499 return nil 500 } 501 502 // Addr returns the listener's network address, a PipeAddr. 503 func (l *PipeListener) Addr() net.Addr { return l.addr } 504 505 // PipeConn is the implementation of the net.Conn interface for named pipe connections. 506 type PipeConn struct { 507 handle syscall.Handle 508 addr PipeAddr 509 510 // these aren't actually used yet 511 readDeadline *time.Time 512 writeDeadline *time.Time 513 } 514 515 type iodata struct { 516 n uint32 517 err error 518 } 519 520 // completeRequest looks at iodata to see if a request is pending. If so, it waits for it to either complete or to 521 // abort due to hitting the specified deadline. Deadline may be set to nil to wait forever. If no request is pending, 522 // the content of iodata is returned. 523 func (c *PipeConn) completeRequest(data iodata, deadline *time.Time, overlapped *syscall.Overlapped) (int, error) { 524 if data.err == error_io_incomplete || data.err == syscall.ERROR_IO_PENDING { 525 var timer <-chan time.Time 526 if deadline != nil { 527 if timeDiff := deadline.Sub(time.Now()); timeDiff > 0 { 528 timer = time.After(timeDiff) 529 } 530 } 531 done := make(chan iodata) 532 go func() { 533 n, err := waitForCompletion(c.handle, overlapped) 534 done <- iodata{n, err} 535 }() 536 select { 537 case data = <-done: 538 case <-timer: 539 syscall.CancelIoEx(c.handle, overlapped) 540 data = iodata{0, timeout(c.addr.String())} 541 } 542 } 543 // Windows will produce ERROR_BROKEN_PIPE upon closing 544 // a handle on the other end of a connection. Go RPC 545 // expects an io.EOF error in this case. 546 if data.err == syscall.ERROR_BROKEN_PIPE { 547 data.err = io.EOF 548 } 549 return int(data.n), data.err 550 } 551 552 // Read implements the net.Conn Read method. 553 func (c *PipeConn) Read(b []byte) (int, error) { 554 // Use ReadFile() rather than Read() because the latter 555 // contains a workaround that eats ERROR_BROKEN_PIPE. 556 overlapped, err := newOverlapped() 557 if err != nil { 558 return 0, err 559 } 560 defer syscall.CloseHandle(overlapped.HEvent) 561 var n uint32 562 err = syscall.ReadFile(c.handle, b, &n, overlapped) 563 return c.completeRequest(iodata{n, err}, c.readDeadline, overlapped) 564 } 565 566 // Write implements the net.Conn Write method. 567 func (c *PipeConn) Write(b []byte) (int, error) { 568 overlapped, err := newOverlapped() 569 if err != nil { 570 return 0, err 571 } 572 defer syscall.CloseHandle(overlapped.HEvent) 573 var n uint32 574 err = syscall.WriteFile(c.handle, b, &n, overlapped) 575 return c.completeRequest(iodata{n, err}, c.writeDeadline, overlapped) 576 } 577 578 // Close closes the connection. 579 func (c *PipeConn) Close() error { 580 return syscall.CloseHandle(c.handle) 581 } 582 583 // LocalAddr returns the local network address. 584 func (c *PipeConn) LocalAddr() net.Addr { 585 return c.addr 586 } 587 588 // RemoteAddr returns the remote network address. 589 func (c *PipeConn) RemoteAddr() net.Addr { 590 // not sure what to do here, we don't have remote addr.... 591 return c.addr 592 } 593 594 // SetDeadline implements the net.Conn SetDeadline method. 595 // Note that timeouts are only supported on Windows Vista/Server 2008 and above 596 func (c *PipeConn) SetDeadline(t time.Time) error { 597 c.SetReadDeadline(t) 598 c.SetWriteDeadline(t) 599 return nil 600 } 601 602 // SetReadDeadline implements the net.Conn SetReadDeadline method. 603 // Note that timeouts are only supported on Windows Vista/Server 2008 and above 604 func (c *PipeConn) SetReadDeadline(t time.Time) error { 605 c.readDeadline = &t 606 return nil 607 } 608 609 // SetWriteDeadline implements the net.Conn SetWriteDeadline method. 610 // Note that timeouts are only supported on Windows Vista/Server 2008 and above 611 func (c *PipeConn) SetWriteDeadline(t time.Time) error { 612 c.writeDeadline = &t 613 return nil 614 } 615 616 // PipeAddr represents the address of a named pipe. 617 type PipeAddr string 618 619 // Network returns the address's network name, "pipe". 620 func (a PipeAddr) Network() string { return "pipe" } 621 622 // String returns the address of the pipe 623 func (a PipeAddr) String() string { 624 return string(a) 625 } 626 627 // createPipe is a helper function to make sure we always create pipes 628 // with the same arguments, since subsequent calls to create pipe need 629 // to use the same arguments as the first one. If first is set, fail 630 // if the pipe already exists. 631 func createPipe(address string, first bool) (syscall.Handle, error) { 632 n, err := syscall.UTF16PtrFromString(address) 633 if err != nil { 634 return 0, err 635 } 636 mode := uint32(pipe_access_duplex | syscall.FILE_FLAG_OVERLAPPED) 637 if first { 638 mode |= file_flag_first_pipe_instance 639 } 640 return createNamedPipe(n, 641 mode, 642 pipe_type_byte, 643 pipe_unlimited_instances, 644 512, 512, 0, nil) 645 } 646 647 func badAddr(addr string) PipeError { 648 return PipeError{fmt.Sprintf("Invalid pipe address '%s'.", addr), false} 649 } 650 func timeout(addr string) PipeError { 651 return PipeError{fmt.Sprintf("Pipe IO timed out waiting for '%s'", addr), true} 652 } 653 654 func newIpcClient(cfg IpcConfig, codec codec.Codec) (*ipcClient, error) { 655 c, err := Dial(cfg.Endpoint) 656 if err != nil { 657 return nil, err 658 } 659 660 coder := codec.New(c) 661 msg := shared.Request{ 662 Id: 0, 663 Method: useragent.EnableUserAgentMethod, 664 Jsonrpc: shared.JsonRpcVersion, 665 Params: []byte("[]"), 666 } 667 668 coder.WriteResponse(msg) 669 coder.Recv() 670 671 return &ipcClient{cfg.Endpoint, c, codec, coder}, nil 672 } 673 674 func (self *ipcClient) reconnect() error { 675 c, err := Dial(self.endpoint) 676 if err == nil { 677 self.coder = self.codec.New(c) 678 679 req := shared.Request{ 680 Id: 0, 681 Method: useragent.EnableUserAgentMethod, 682 Jsonrpc: shared.JsonRpcVersion, 683 Params: []byte("[]"), 684 } 685 self.coder.WriteResponse(req) 686 self.coder.Recv() 687 } 688 return err 689 } 690 691 func startIpc(cfg IpcConfig, codec codec.Codec, initializer func(conn net.Conn) (shared.EthereumApi, error)) error { 692 os.Remove(cfg.Endpoint) // in case it still exists from a previous run 693 694 l, err := Listen(cfg.Endpoint) 695 if err != nil { 696 return err 697 } 698 os.Chmod(cfg.Endpoint, 0600) 699 700 go func() { 701 for { 702 conn, err := l.Accept() 703 if err != nil { 704 glog.V(logger.Error).Infof("Error accepting ipc connection - %v\n", err) 705 continue 706 } 707 708 id := newIpcConnId() 709 glog.V(logger.Debug).Infof("New IPC connection with id %06d started\n", id) 710 711 api, err := initializer(conn) 712 if err != nil { 713 glog.V(logger.Error).Infof("Unable to initialize IPC connection - %v\n", err) 714 conn.Close() 715 continue 716 } 717 718 go handle(id, conn, api, codec) 719 } 720 721 os.Remove(cfg.Endpoint) 722 }() 723 724 glog.V(logger.Info).Infof("IPC service started (%s)\n", cfg.Endpoint) 725 726 return nil 727 }