Index: /trunk/conn.go
===================================================================
--- /trunk/conn.go	(revision 756)
+++ /trunk/conn.go	(revision 757)
@@ -218,5 +218,5 @@
 // If the connection is closed before the message is sent, SendMessage silently
 // drops the message.
-func (c *conn) SendMessage(msg *irc.Message) {
+func (c *conn) SendMessage(ctx context.Context, msg *irc.Message) {
 	c.lock.Lock()
 	defer c.lock.Unlock()
@@ -225,5 +225,11 @@
 		return
 	}
-	c.outgoing <- msg
+
+	select {
+	case c.outgoing <- msg:
+		// Success
+	case <-ctx.Done():
+		c.logger.Printf("failed to send message: %v", ctx.Err())
+	}
 }
 
Index: /trunk/downstream.go
===================================================================
--- /trunk/downstream.go	(revision 756)
+++ /trunk/downstream.go	(revision 757)
@@ -552,5 +552,5 @@
 
 	dc.srv.metrics.downstreamOutMessagesTotal.Inc()
-	dc.conn.SendMessage(msg)
+	dc.conn.SendMessage(context.TODO(), msg)
 }
 
@@ -1667,5 +1667,5 @@
 				return
 			}
-			uc.SendMessageLabeled(dc.id, &irc.Message{
+			uc.SendMessageLabeled(ctx, dc.id, &irc.Message{
 				Command: "NICK",
 				Params:  []string{nick},
@@ -1701,5 +1701,5 @@
 			// support setname
 			if uc := n.conn; uc != nil && uc.caps["setname"] {
-				uc.SendMessageLabeled(dc.id, &irc.Message{
+				uc.SendMessageLabeled(ctx, dc.id, &irc.Message{
 					Command: "SETNAME",
 					Params:  []string{realname},
@@ -1776,5 +1776,5 @@
 				params = append(params, key)
 			}
-			uc.SendMessageLabeled(dc.id, &irc.Message{
+			uc.SendMessageLabeled(ctx, dc.id, &irc.Message{
 				Command: "JOIN",
 				Params:  params,
@@ -1836,5 +1836,5 @@
 					params = append(params, reason)
 				}
-				uc.SendMessageLabeled(dc.id, &irc.Message{
+				uc.SendMessageLabeled(ctx, dc.id, &irc.Message{
 					Command: "PART",
 					Params:  params,
@@ -1897,5 +1897,5 @@
 				params = append(params, reason)
 			}
-			uc.SendMessageLabeled(dc.id, &irc.Message{
+			uc.SendMessageLabeled(ctx, dc.id, &irc.Message{
 				Command: "KICK",
 				Params:  params,
@@ -1916,5 +1916,5 @@
 			if modeStr != "" {
 				if uc := dc.upstream(); uc != nil {
-					uc.SendMessageLabeled(dc.id, &irc.Message{
+					uc.SendMessageLabeled(ctx, dc.id, &irc.Message{
 						Command: "MODE",
 						Params:  []string{uc.nick, modeStr},
@@ -1957,5 +1957,5 @@
 			params := []string{upstreamName, modeStr}
 			params = append(params, msg.Params[2:]...)
-			uc.SendMessageLabeled(dc.id, &irc.Message{
+			uc.SendMessageLabeled(ctx, dc.id, &irc.Message{
 				Command: "MODE",
 				Params:  params,
@@ -2006,5 +2006,5 @@
 		if len(msg.Params) > 1 { // setting topic
 			topic := msg.Params[1]
-			uc.SendMessageLabeled(dc.id, &irc.Message{
+			uc.SendMessageLabeled(ctx, dc.id, &irc.Message{
 				Command: "TOPIC",
 				Params:  []string{upstreamName, topic},
@@ -2071,5 +2071,5 @@
 			} else {
 				// NAMES on a channel we have not joined, ask upstream
-				uc.SendMessageLabeled(dc.id, &irc.Message{
+				uc.SendMessageLabeled(ctx, dc.id, &irc.Message{
 					Command: "NAMES",
 					Params:  []string{upstreamName},
@@ -2271,5 +2271,5 @@
 		}
 
-		uc.SendMessageLabeled(dc.id, &irc.Message{
+		uc.SendMessageLabeled(ctx, dc.id, &irc.Message{
 			Command: "WHOIS",
 			Params:  params,
@@ -2348,5 +2348,5 @@
 				unmarshaledText = dc.unmarshalText(uc, text)
 			}
-			uc.SendMessageLabeled(dc.id, &irc.Message{
+			uc.SendMessageLabeled(ctx, dc.id, &irc.Message{
 				Tags:    tags,
 				Command: msg.Command,
@@ -2399,5 +2399,5 @@
 			}
 
-			uc.SendMessageLabeled(dc.id, &irc.Message{
+			uc.SendMessageLabeled(ctx, dc.id, &irc.Message{
 				Tags:    tags,
 				Command: "TAGMSG",
@@ -2431,5 +2431,5 @@
 		uc := ucChannel
 
-		uc.SendMessageLabeled(dc.id, &irc.Message{
+		uc.SendMessageLabeled(ctx, dc.id, &irc.Message{
 			Command: "INVITE",
 			Params:  []string{upstreamUser, upstreamChannel},
@@ -2851,5 +2851,5 @@
 		}
 
-		uc.SendMessageLabeled(dc.id, msg)
+		uc.SendMessageLabeled(ctx, dc.id, msg)
 	}
 	return nil
Index: /trunk/service.go
===================================================================
--- /trunk/service.go	(revision 756)
+++ /trunk/service.go	(revision 757)
@@ -617,5 +617,5 @@
 		return fmt.Errorf("failed to parse command %q: %v", params[1], err)
 	}
-	uc.SendMessage(m)
+	uc.SendMessage(ctx, m)
 
 	sendServicePRIVMSG(dc, fmt.Sprintf("sent command to %q", net.GetName()))
Index: /trunk/upstream.go
===================================================================
--- /trunk/upstream.go	(revision 756)
+++ /trunk/upstream.go	(revision 757)
@@ -343,5 +343,5 @@
 		return
 	}
-	uc.SendMessage(uc.pendingCmds[cmd][0].msg)
+	uc.SendMessage(context.TODO(), uc.pendingCmds[cmd][0].msg)
 }
 
@@ -451,5 +451,5 @@
 	switch msg.Command {
 	case "PING":
-		uc.SendMessage(&irc.Message{
+		uc.SendMessage(ctx, &irc.Message{
 			Command: "PONG",
 			Params:  msg.Params,
@@ -530,5 +530,5 @@
 			}
 
-			uc.SendMessage(&irc.Message{
+			uc.SendMessage(ctx, &irc.Message{
 				Command: "CAP",
 				Params:  []string{"END"},
@@ -584,5 +584,5 @@
 		var challengeStr string
 		if err := parseMessageParams(msg, &challengeStr); err != nil {
-			uc.SendMessage(&irc.Message{
+			uc.SendMessage(ctx, &irc.Message{
 				Command: "AUTHENTICATE",
 				Params:  []string{"*"},
@@ -596,5 +596,5 @@
 			challenge, err = base64.StdEncoding.DecodeString(challengeStr)
 			if err != nil {
-				uc.SendMessage(&irc.Message{
+				uc.SendMessage(ctx, &irc.Message{
 					Command: "AUTHENTICATE",
 					Params:  []string{"*"},
@@ -613,5 +613,5 @@
 		}
 		if err != nil {
-			uc.SendMessage(&irc.Message{
+			uc.SendMessage(ctx, &irc.Message{
 				Command: "AUTHENTICATE",
 				Params:  []string{"*"},
@@ -626,5 +626,5 @@
 		}
 
-		uc.SendMessage(&irc.Message{
+		uc.SendMessage(ctx, &irc.Message{
 			Command: "AUTHENTICATE",
 			Params:  []string{respStr},
@@ -670,5 +670,5 @@
 
 		if !uc.registered {
-			uc.SendMessage(&irc.Message{
+			uc.SendMessage(ctx, &irc.Message{
 				Command: "CAP",
 				Params:  []string{"END"},
@@ -708,5 +708,5 @@
 
 			for _, msg := range join(channels, keys) {
-				uc.SendMessage(msg)
+				uc.SendMessage(ctx, msg)
 			}
 		}
@@ -932,5 +932,5 @@
 				uc.updateChannelAutoDetach(ch)
 
-				uc.SendMessage(&irc.Message{
+				uc.SendMessage(ctx, &irc.Message{
 					Command: "MODE",
 					Params:  []string{ch},
@@ -1532,5 +1532,5 @@
 			if found {
 				uc.logger.Printf("desired nick %q is now available", wantNick)
-				uc.SendMessage(&irc.Message{
+				uc.SendMessage(ctx, &irc.Message{
 					Command: "NICK",
 					Params:  []string{wantNick},
@@ -1712,5 +1712,5 @@
 			uc.nickCM = uc.network.casemap(uc.nick)
 			uc.logger.Printf("desired nick is not available, falling back to %q", uc.nick)
-			uc.SendMessage(&irc.Message{
+			uc.SendMessage(ctx, &irc.Message{
 				Command: "NICK",
 				Params:  []string{uc.nick},
@@ -1826,5 +1826,5 @@
 	}
 
-	uc.SendMessage(&irc.Message{
+	uc.SendMessage(context.TODO(), &irc.Message{
 		Command: "CAP",
 		Params:  []string{"REQ", strings.Join(requestCaps, " ")},
@@ -1883,5 +1883,5 @@
 		}
 
-		uc.SendMessage(&irc.Message{
+		uc.SendMessage(context.TODO(), &irc.Message{
 			Command: "AUTHENTICATE",
 			Params:  []string{auth.Mechanism},
@@ -1903,4 +1903,6 @@
 
 func (uc *upstreamConn) register() {
+	ctx := context.TODO()
+
 	uc.nick = GetNick(&uc.user.User, &uc.network.Network)
 	uc.nickCM = uc.network.casemap(uc.nick)
@@ -1908,5 +1910,5 @@
 	uc.realname = GetRealname(&uc.user.User, &uc.network.Network)
 
-	uc.SendMessage(&irc.Message{
+	uc.SendMessage(ctx, &irc.Message{
 		Command: "CAP",
 		Params:  []string{"LS", "302"},
@@ -1914,5 +1916,5 @@
 
 	if uc.network.Pass != "" {
-		uc.SendMessage(&irc.Message{
+		uc.SendMessage(ctx, &irc.Message{
 			Command: "PASS",
 			Params:  []string{uc.network.Pass},
@@ -1920,9 +1922,9 @@
 	}
 
-	uc.SendMessage(&irc.Message{
+	uc.SendMessage(ctx, &irc.Message{
 		Command: "NICK",
 		Params:  []string{uc.nick},
 	})
-	uc.SendMessage(&irc.Message{
+	uc.SendMessage(ctx, &irc.Message{
 		Command: "USER",
 		Params:  []string{uc.username, "0", "*", uc.realname},
@@ -1961,5 +1963,5 @@
 			uc.logger.Printf("failed to parse connect command %q: %v", command, err)
 		} else {
-			uc.SendMessage(m)
+			uc.SendMessage(context.TODO(), m)
 		}
 	}
@@ -1983,5 +1985,5 @@
 }
 
-func (uc *upstreamConn) SendMessage(msg *irc.Message) {
+func (uc *upstreamConn) SendMessage(ctx context.Context, msg *irc.Message) {
 	if !uc.caps["message-tags"] {
 		msg = msg.Copy()
@@ -1990,8 +1992,8 @@
 
 	uc.srv.metrics.upstreamOutMessagesTotal.Inc()
-	uc.conn.SendMessage(msg)
-}
-
-func (uc *upstreamConn) SendMessageLabeled(downstreamID uint64, msg *irc.Message) {
+	uc.conn.SendMessage(ctx, msg)
+}
+
+func (uc *upstreamConn) SendMessageLabeled(ctx context.Context, downstreamID uint64, msg *irc.Message) {
 	if uc.caps["labeled-response"] {
 		if msg.Tags == nil {
@@ -2001,5 +2003,5 @@
 		uc.nextLabelID++
 	}
-	uc.SendMessage(msg)
+	uc.SendMessage(ctx, msg)
 }
 
@@ -2074,4 +2076,6 @@
 
 func (uc *upstreamConn) updateAway() {
+	ctx := context.TODO()
+
 	away := true
 	uc.forEachDownstream(func(*downstreamConn) {
@@ -2082,10 +2086,10 @@
 	}
 	if away {
-		uc.SendMessage(&irc.Message{
+		uc.SendMessage(ctx, &irc.Message{
 			Command: "AWAY",
 			Params:  []string{"Auto away"},
 		})
 	} else {
-		uc.SendMessage(&irc.Message{
+		uc.SendMessage(ctx, &irc.Message{
 			Command: "AWAY",
 		})
@@ -2110,4 +2114,6 @@
 		return
 	}
+
+	ctx := context.TODO()
 
 	add := make(map[string]struct{})
@@ -2149,5 +2155,5 @@
 	if removeAll && len(addList) == 0 && len(removeList) > 0 {
 		// Optimization when the last MONITOR-aware downstream disconnects
-		uc.SendMessage(&irc.Message{
+		uc.SendMessage(ctx, &irc.Message{
 			Command: "MONITOR",
 			Params:  []string{"C"},
@@ -2157,5 +2163,5 @@
 		msgs = append(msgs, generateMonitor("+", addList)...)
 		for _, msg := range msgs {
-			uc.SendMessage(msg)
+			uc.SendMessage(ctx, msg)
 		}
 	}
