forked from panjf2000/gnet
-
Notifications
You must be signed in to change notification settings - Fork 4
/
connection_linux.go
70 lines (65 loc) · 2.55 KB
/
connection_linux.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
/*
* Copyright (c) 2021 The Gnet Authors. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package gnet
import (
"io"
"golang.org/x/sys/unix"
"github.com/panjf2000/gnet/v2/internal/netpoll"
)
func (c *conn) processIO(_ int, ev netpoll.IOEvent, _ netpoll.IOFlags) error {
el := c.loop
// First check for any unexpected non-IO events.
// For these events we just close the connection directly.
if ev&(netpoll.ErrEvents|unix.EPOLLRDHUP) != 0 && ev&netpoll.ReadWriteEvents == 0 {
c.outboundBuffer.Release() // don't bother to write to a connection that is already broken
return el.close(c, io.EOF)
}
// Secondly, check for EPOLLOUT before EPOLLIN, the former has a higher priority
// than the latter regardless of the aliveness of the current connection:
//
// 1. When the connection is alive and the system is overloaded, we want to
// offload the incoming traffic by writing all pending data back to the remotes
// before continuing to read and handle requests.
// 2. When the connection is dead, we need to try writing any pending data back
// to the remote first and then close the connection.
//
// We perform eventloop.write for EPOLLOUT because it can take good care of either case.
if ev&(netpoll.WriteEvents|netpoll.ErrEvents) != 0 {
if err := el.write(c); err != nil {
return err
}
}
// Check for EPOLLIN before EPOLLRDHUP in case that there are pending data in
// the socket buffer.
if ev&(netpoll.ReadEvents|netpoll.ErrEvents) != 0 {
if err := el.read(c); err != nil {
return err
}
}
// Ultimately, check for EPOLLRDHUP, this event indicates that the remote has
// either closed connection or shut down the writing half of the connection.
if ev&unix.EPOLLRDHUP != 0 && c.opened {
if ev&unix.EPOLLIN == 0 { // unreadable EPOLLRDHUP, close the connection directly
return el.close(c, io.EOF)
}
// Received the event of EPOLLIN|EPOLLRDHUP, but the previous eventloop.read
// failed to drain the socket buffer, so we ensure to get it done this time.
c.isEOF = true
return el.read(c)
}
return nil
}