Changeset 13 in code for trunk/server.go


Ignore:
Timestamp:
Feb 6, 2020, 3:18:19 PM (5 years ago)
Author:
contact
Message:

Split downstram and upstream code into separate files

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/server.go

    r12 r13  
    22
    33import (
    4         "crypto/tls"
    54        "fmt"
    6         "io"
    7         "log"
    85        "net"
    96
     
    1411        Print(v ...interface{})
    1512        Printf(format string, v ...interface{})
    16 }
    17 
    18 type ircError struct {
    19         Message *irc.Message
    20 }
    21 
    22 func newUnknownCommandError(cmd string) ircError {
    23         return ircError{&irc.Message{
    24                 Command: irc.ERR_UNKNOWNCOMMAND,
    25                 Params: []string{
    26                         "*",
    27                         cmd,
    28                         "Unknown command",
    29                 },
    30         }}
    31 }
    32 
    33 func newNeedMoreParamsError(cmd string) ircError {
    34         return ircError{&irc.Message{
    35                 Command: irc.ERR_NEEDMOREPARAMS,
    36                 Params: []string{
    37                         "*",
    38                         cmd,
    39                         "Not enough parameters",
    40                 },
    41         }}
    42 }
    43 
    44 func (err ircError) Error() string {
    45         return err.Message.String()
    46 }
    47 
    48 type downstreamConn struct {
    49         net        net.Conn
    50         irc        *irc.Conn
    51         srv        *Server
    52         registered bool
    53         closed     bool
    54         nick       string
    55         username   string
    56         realname   string
    57 }
    58 
    59 func (c *downstreamConn) Close() error {
    60         if err := c.net.Close(); err != nil {
    61                 return err
    62         }
    63         c.closed = true
    64         return nil
    65 }
    66 
    67 func (c *downstreamConn) WriteMessage(msg *irc.Message) error {
    68         msg.Prefix = c.srv.prefix()
    69         return c.irc.WriteMessage(msg)
    70 }
    71 
    72 func (c *downstreamConn) handleMessage(msg *irc.Message) error {
    73         switch msg.Command {
    74         case "PING":
    75                 // TODO: handle params
    76                 return c.WriteMessage(&irc.Message{
    77                         Command: "PONG",
    78                         Params:  []string{c.srv.Hostname},
    79                 })
    80         default:
    81                 if c.registered {
    82                         return c.handleMessageRegistered(msg)
    83                 } else {
    84                         return c.handleMessageUnregistered(msg)
    85                 }
    86         }
    87 }
    88 
    89 func (c *downstreamConn) handleMessageUnregistered(msg *irc.Message) error {
    90         switch msg.Command {
    91         case "NICK":
    92                 if len(msg.Params) != 1 {
    93                         return newNeedMoreParamsError(msg.Command)
    94                 }
    95                 c.nick = msg.Params[0]
    96         case "USER":
    97                 if len(msg.Params) != 4 {
    98                         return newNeedMoreParamsError(msg.Command)
    99                 }
    100                 c.username = "~" + msg.Params[0]
    101                 c.realname = msg.Params[3]
    102         case "QUIT":
    103                 return c.Close()
    104         default:
    105                 return newUnknownCommandError(msg.Command)
    106         }
    107         if c.username != "" && c.nick != "" {
    108                 return c.register()
    109         }
    110         return nil
    111 }
    112 
    113 func (c *downstreamConn) register() error {
    114         c.registered = true
    115 
    116         err := c.WriteMessage(&irc.Message{
    117                 Command: irc.RPL_WELCOME,
    118                 Params:  []string{c.nick, "Welcome to jounce, " + c.nick},
    119         })
    120         if err != nil {
    121                 return err
    122         }
    123 
    124         err = c.WriteMessage(&irc.Message{
    125                 Command: irc.RPL_YOURHOST,
    126                 Params:  []string{c.nick, "Your host is " + c.srv.Hostname},
    127         })
    128         if err != nil {
    129                 return err
    130         }
    131 
    132         err = c.WriteMessage(&irc.Message{
    133                 Command: irc.RPL_CREATED,
    134                 Params:  []string{c.nick, "This server was created <datetime>"}, // TODO
    135         })
    136         if err != nil {
    137                 return err
    138         }
    139 
    140         err = c.WriteMessage(&irc.Message{
    141                 Command: irc.RPL_MYINFO,
    142                 Params:  []string{c.nick, c.srv.Hostname, "unknown", "", ""},
    143         })
    144         if err != nil {
    145                 return err
    146         }
    147 
    148         err = c.WriteMessage(&irc.Message{
    149                 Command: irc.ERR_NOMOTD,
    150                 Params:  []string{c.nick, "No MOTD"},
    151         })
    152         if err != nil {
    153                 return err
    154         }
    155 
    156         return nil
    157 }
    158 
    159 func (c *downstreamConn) handleMessageRegistered(msg *irc.Message) error {
    160         switch msg.Command {
    161         case "NICK", "USER":
    162                 return ircError{&irc.Message{
    163                         Command: irc.ERR_ALREADYREGISTERED,
    164                         Params: []string{
    165                                 c.nick,
    166                                 "You may not reregister",
    167                         },
    168                 }}
    169         case "QUIT":
    170                 return c.Close()
    171         default:
    172                 return newUnknownCommandError(msg.Command)
    173         }
    174 }
    175 
    176 type upstreamConn struct {
    177         net net.Conn
    178         irc *irc.Conn
    179         srv *Server
    180 }
    181 
    182 func (c *upstreamConn) handleMessage(msg *irc.Message) error {
    183         switch msg.Command {
    184         case "PING":
    185                 // TODO: handle params
    186                 return c.irc.WriteMessage(&irc.Message{
    187                         Command: "PONG",
    188                         Params:  []string{c.srv.Hostname},
    189                 })
    190         default:
    191                 c.srv.Logger.Printf("Unhandled upstream message: %v", msg)
    192                 return nil
    193         }
    19413}
    19514
     
    21130}
    21231
    213 func (s *Server) handleConn(netConn net.Conn) error {
    214         s.Logger.Printf("Handling connection from %v", netConn.RemoteAddr())
    215 
    216         c := downstreamConn{net: netConn, irc: irc.NewConn(netConn), srv: s}
    217         defer c.Close()
    218         for {
    219                 msg, err := c.irc.ReadMessage()
    220                 if err == io.EOF {
    221                         break
    222                 } else if err != nil {
    223                         return fmt.Errorf("failed to read IRC command: %v", err)
    224                 }
    225                 s.Logger.Printf("Downstream message: %v", msg)
    226 
    227                 err = c.handleMessage(msg)
    228                 if ircErr, ok := err.(ircError); ok {
    229                         ircErr.Message.Prefix = s.prefix()
    230                         if err := c.WriteMessage(ircErr.Message); err != nil {
    231                                 return fmt.Errorf("failed to write IRC reply: %v", err)
    232                         }
    233                 } else if err != nil {
    234                         return fmt.Errorf("failed to handle IRC command %q: %v", msg.Command, err)
    235                 }
    236 
    237                 if c.closed {
    238                         return nil
    239                 }
    240         }
    241 
    242         return c.Close()
    243 }
    244 
    245 func (s *Server) connect(upstream *Upstream) error {
    246         s.Logger.Printf("Connecting to %v", upstream.Addr)
    247 
    248         netConn, err := tls.Dial("tcp", upstream.Addr, nil)
    249         if err != nil {
    250                 return fmt.Errorf("failed to dial %q: %v", upstream.Addr, err)
    251         }
    252 
    253         c := upstreamConn{net: netConn, irc: irc.NewConn(netConn), srv: s}
    254         defer netConn.Close()
    255 
    256         err = c.irc.WriteMessage(&irc.Message{
    257                 Command: "NICK",
    258                 Params:  []string{upstream.Nick},
    259         })
    260         if err != nil {
    261                 return err
    262         }
    263 
    264         err = c.irc.WriteMessage(&irc.Message{
    265                 Command: "USER",
    266                 Params:  []string{upstream.Username, "0", "*", upstream.Realname},
    267         })
    268         if err != nil {
    269                 return err
    270         }
    271 
    272         for {
    273                 msg, err := c.irc.ReadMessage()
    274                 if err == io.EOF {
    275                         break
    276                 } else if err != nil {
    277                         return fmt.Errorf("failed to read IRC command: %v", err)
    278                 }
    279 
    280                 if err := c.handleMessage(msg); err != nil {
    281                         return err
    282                 }
    283         }
    284 
    285         return netConn.Close()
    286 }
    287 
    28832func (s *Server) Run() {
    28933        for i := range s.Upstreams {
     
    29135                // TODO: retry connecting
    29236                go func() {
    293                         if err := s.connect(upstream); err != nil {
     37                        if err := connect(s, upstream); err != nil {
    29438                                s.Logger.Printf("Failed to connect to upstream server %q: %v", upstream.Addr, err)
    29539                        }
     
    30650
    30751                go func() {
    308                         if err := s.handleConn(c); err != nil {
    309                                 log.Printf("error handling connection: %v", err)
     52                        if err := handleConn(s, c); err != nil {
     53                                s.Logger.Printf("Error handling connection: %v", err)
    31054                        }
    31155                }()
Note: See TracChangeset for help on using the changeset viewer.