utils.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. /*
  2. * Copyright (c) 2016, Psiphon Inc.
  3. * All rights reserved.
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. *
  18. */
  19. package server
  20. import (
  21. "fmt"
  22. "io"
  23. "strings"
  24. "sync/atomic"
  25. )
  26. // IntentionalPanicError is an error type that is used
  27. // when calling panic() in a situation where recovers
  28. // should propagate the panic.
  29. type IntentionalPanicError struct {
  30. message string
  31. }
  32. // NewIntentionalPanicError creates a new IntentionalPanicError.
  33. func NewIntentionalPanicError(errorMessage string) error {
  34. return IntentionalPanicError{
  35. message: fmt.Sprintf("intentional panic error: %s", errorMessage)}
  36. }
  37. // Error implements the error interface.
  38. func (err IntentionalPanicError) Error() string {
  39. return err.message
  40. }
  41. // PanickingLogWriter wraps an io.Writer and intentionally
  42. // panics when a Write() fails.
  43. type PanickingLogWriter struct {
  44. name string
  45. writer io.Writer
  46. }
  47. // NewPanickingLogWriter creates a new PanickingLogWriter.
  48. func NewPanickingLogWriter(
  49. name string, writer io.Writer) *PanickingLogWriter {
  50. return &PanickingLogWriter{
  51. name: name,
  52. writer: writer,
  53. }
  54. }
  55. // Write implements the io.Writer interface.
  56. func (w *PanickingLogWriter) Write(p []byte) (n int, err error) {
  57. n, err = w.writer.Write(p)
  58. if err != nil {
  59. panic(
  60. NewIntentionalPanicError(
  61. fmt.Sprintf("fatal write to %s failed: %s", w.name, err)))
  62. }
  63. return
  64. }
  65. func min(a, b int) int {
  66. if a < b {
  67. return a
  68. }
  69. return b
  70. }
  71. func greaterThanSwapInt64(addr *int64, new int64) bool {
  72. old := atomic.LoadInt64(addr)
  73. if new > old {
  74. return atomic.CompareAndSwapInt64(addr, old, new)
  75. }
  76. return false
  77. }
  78. var expectedTunnelIOErrorSubstrings = []string{
  79. "EOF",
  80. "use of closed network connection",
  81. "connection reset by peer",
  82. "connection has closed",
  83. "broken pipe",
  84. "i/o timeout",
  85. "deadline exceeded",
  86. "NetworkIdleTimeout",
  87. "PeerGoingAway",
  88. "Application error 0x0",
  89. "No recent network activity",
  90. }
  91. // isExpectedTunnelIOError checks if the error indicates failure due to tunnel
  92. // I/O timing out, use of a closed tunnel, etc. This is used to avoid logging
  93. // noise in cases where sending messages through the tunnel fail due regular,
  94. // expected tunnel failure conditions.
  95. //
  96. // Limitations introduced by error type wrapping and lack of common error
  97. // types across all network protcol layers means this function uses
  98. // heuristical error text substring matching and may fall out of sync with new
  99. // protocols/error messages. As such, this function should only be used for
  100. // the intended log noise purpose.
  101. func isExpectedTunnelIOError(err error) bool {
  102. errString := err.Error()
  103. for _, substring := range expectedTunnelIOErrorSubstrings {
  104. if strings.Contains(errString, substring) {
  105. return true
  106. }
  107. }
  108. return false
  109. }