1package srslog
2
3import (
4	"crypto/tls"
5	"net"
6)
7
8// dialerFunctionWrapper is a simple object that consists of a dialer function
9// and its name. This is primarily for testing, so we can make sure that the
10// getDialer method returns the correct dialer function. However, if you ever
11// find that you need to check which dialer function you have, this would also
12// be useful for you without having to use reflection.
13type dialerFunctionWrapper struct {
14	Name   string
15	Dialer func() (serverConn, string, error)
16}
17
18// Call the wrapped dialer function and return its return values.
19func (df dialerFunctionWrapper) Call() (serverConn, string, error) {
20	return df.Dialer()
21}
22
23// getDialer returns a "dialer" function that can be called to connect to a
24// syslog server.
25//
26// Each dialer function is responsible for dialing the remote host and returns
27// a serverConn, the hostname (or a default if the Writer has not specified a
28// hostname), and an error in case dialing fails.
29//
30// The reason for separate dialers is that different network types may need
31// to dial their connection differently, yet still provide a net.Conn interface
32// that you can use once they have dialed. Rather than an increasingly long
33// conditional, we have a map of network -> dialer function (with a sane default
34// value), and adding a new network type is as easy as writing the dialer
35// function and adding it to the map.
36func (w *Writer) getDialer() dialerFunctionWrapper {
37	dialers := map[string]dialerFunctionWrapper{
38		"":        dialerFunctionWrapper{"unixDialer", w.unixDialer},
39		"tcp+tls": dialerFunctionWrapper{"tlsDialer", w.tlsDialer},
40	}
41	dialer, ok := dialers[w.network]
42	if !ok {
43		dialer = dialerFunctionWrapper{"basicDialer", w.basicDialer}
44	}
45	return dialer
46}
47
48// unixDialer uses the unixSyslog method to open a connection to the syslog
49// daemon running on the local machine.
50func (w *Writer) unixDialer() (serverConn, string, error) {
51	sc, err := unixSyslog()
52	hostname := w.hostname
53	if hostname == "" {
54		hostname = "localhost"
55	}
56	return sc, hostname, err
57}
58
59// tlsDialer connects to TLS over TCP, and is used for the "tcp+tls" network
60// type.
61func (w *Writer) tlsDialer() (serverConn, string, error) {
62	c, err := tls.Dial("tcp", w.raddr, w.tlsConfig)
63	var sc serverConn
64	hostname := w.hostname
65	if err == nil {
66		sc = &netConn{conn: c}
67		if hostname == "" {
68			hostname = c.LocalAddr().String()
69		}
70	}
71	return sc, hostname, err
72}
73
74// basicDialer is the most common dialer for syslog, and supports both TCP and
75// UDP connections.
76func (w *Writer) basicDialer() (serverConn, string, error) {
77	c, err := net.Dial(w.network, w.raddr)
78	var sc serverConn
79	hostname := w.hostname
80	if err == nil {
81		sc = &netConn{conn: c}
82		if hostname == "" {
83			hostname = c.LocalAddr().String()
84		}
85	}
86	return sc, hostname, err
87}
88