forked from vjeantet/ldapserver
-
Notifications
You must be signed in to change notification settings - Fork 2
/
server.go
139 lines (117 loc) · 3.22 KB
/
server.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package ldapserver
import (
"bufio"
"errors"
"net"
"sync"
"time"
)
// Server is an LDAP server.
type Server struct {
Listener net.Listener
ReadTimeout time.Duration // optional read timeout
WriteTimeout time.Duration // optional write timeout
wg sync.WaitGroup // group of goroutines (1 by client)
chDone chan bool // Channel Done, value => shutdown
// OnNewConnection, if non-nil, is called on new connections.
// If it returns non-nil, the connection is closed.
OnNewConnection func(c net.Conn) error
// Handler handles ldap message received from client
// it SHOULD "implement" RequestHandler interface
Handler Handler
}
// NewServer return a LDAP Server
func NewServer() *Server {
return &Server{
chDone: make(chan bool),
}
}
// Handle registers the handler for the server.
// If a handler already exists for pattern, Handle panics
func (s *Server) Handle(h Handler) error {
if s.Handler != nil {
return errors.New("LDAP: multiple Handler registrations")
}
s.Handler = h
return nil
}
// ListenAndServe listens on the TCP network address s.Addr and then
// calls Serve to handle requests on incoming connections. If
// s.Addr is blank, ":389" is used.
func (s *Server) ListenAndServe(addr string, options ...func(*Server)) error {
if addr == "" {
addr = ":389"
}
var e error
s.Listener, e = net.Listen("tcp", addr)
if e != nil {
return e
}
for _, option := range options {
option(s)
}
return s.serve()
}
// Handle requests messages on the ln listener
func (s *Server) serve() error {
defer s.Listener.Close()
if s.Handler == nil {
panic("No LDAP Request Handler defined")
}
i := 0
for {
select {
case <-s.chDone:
s.Listener.Close()
return nil
default:
}
rw, err := s.Listener.Accept()
if s.ReadTimeout != 0 {
rw.SetReadDeadline(time.Now().Add(s.ReadTimeout))
}
if s.WriteTimeout != 0 {
rw.SetWriteDeadline(time.Now().Add(s.WriteTimeout))
}
if nil != err {
if opErr, ok := err.(*net.OpError); ok || opErr.Timeout() {
continue
}
log(rw.RemoteAddr().String(), err.Error())
}
cli, err := s.newClient(rw)
if err != nil {
continue
}
i = i + 1
cli.Numero = i
log(cli.rwc.RemoteAddr().String(), "Connection client [%d] from %s accepted", cli.Numero, cli.rwc.RemoteAddr().String())
s.wg.Add(1)
go cli.serve()
}
}
// Return a new session with the connection
// client has a writer and reader buffer
func (s *Server) newClient(rwc net.Conn) (c *client, err error) {
c = &client{
srv: s,
rwc: rwc,
br: bufio.NewReader(rwc),
bw: bufio.NewWriter(rwc),
}
return c, nil
}
// Termination of the LDAP session is initiated by the server sending a
// Notice of Disconnection. In this case, each
// protocol peer gracefully terminates the LDAP session by ceasing
// exchanges at the LDAP message layer, tearing down any SASL layer,
// tearing down any TLS layer, and closing the transport connection.
// A protocol peer may determine that the continuation of any
// communication would be pernicious, and in this case, it may abruptly
// terminate the session by ceasing communication and closing the
// transport connection.
// In either case, when the LDAP session is terminated.
func (s *Server) Stop() {
close(s.chDone)
s.wg.Wait()
}