1 /*
2  * Copyright 2019, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include "cache.h"
20 #include "frame.h"
21 #include "frame_id.h"
22 #include "macaddress.h"
23 #include "netlink_socket.h"
24 #include "result.h"
25 
26 #include <chrono>
27 #include <functional>
28 #include <memory>
29 #include <queue>
30 
31 struct MacAddress;
32 
33 class LocalConnection {
34 public:
35     using OnFrameCallback = std::function<void (std::unique_ptr<Frame>)>;
36     using OnAckCallback = std::function<void (FrameInfo&)>;
37     using OnErrorCallback = OnAckCallback;
38 
39     LocalConnection(OnFrameCallback onFrameCallback,
40                     OnAckCallback onAckCallback,
41                     OnErrorCallback onErrorCallback);
42     Result init(std::chrono::steady_clock::time_point now);
43 
44     int getFd() const;
45     bool receive();
46     uint32_t cloneFrame(const Frame& frame, const MacAddress& destination);
47     uint32_t transferFrame(std::unique_ptr<Frame> frame,
48                            const MacAddress& destination);
49     bool ackFrame(FrameInfo& info, bool success);
50 
51     std::chrono::steady_clock::time_point getTimeout() const;
52     void onTimeout(std::chrono::steady_clock::time_point now);
53 
54 private:
55     using Timestamp = std::chrono::steady_clock::time_point;
56 
57     Result registerReceiver();
58     static int staticOnMessage(struct nl_msg* msg, void* context);
59     static int staticOnAck(struct nl_msg* msg, void* context);
60     static int staticOnError(struct sockaddr_nl* addr,
61                              struct nlmsgerr* error,
62                              void* context);
63     int onMessage(struct nl_msg* msg);
64     int onFrame(struct nl_msg* msg);
65     std::unique_ptr<Frame> parseFrame(struct nlmsghdr* hdr);
66 
67     int onAck(struct nl_msg* msg);
68     int onError(struct sockaddr_nl* addr, struct nlmsgerr* error);
69     bool sendFrameOnNetlink(const Frame& frame, const MacAddress& dest);
70 
71     OnFrameCallback mOnFrameCallback;
72     OnAckCallback mOnAckCallback;
73     OnErrorCallback mOnErrorCallback;
74 
75     NetlinkSocket mNetlinkSocket;
76     int mNetlinkFamily = -1;
77 
78     // [cookie,transmitter] -> frame.
79     Cache<FrameId, std::unique_ptr<Frame>> mPendingFrames;
80     // sequence number -> [cookie,transmitter]
81     Cache<uint32_t, FrameId> mSequenceNumberCookies;
82 
83     Timestamp mLastCacheTimeUpdate;
84     Timestamp mLastCacheExpiration;
85 
86     // A queue (using an ordered map) with the next timeout mapping to the
87     // cookie and transmitter of the frame to retry. This way we can easily
88     // determine when the next deadline is by looking at the first entry and we
89     // can quickly determine which frames to retry by starting at the beginning.
90     std::priority_queue<std::pair<Timestamp, FrameId>> mRetryQueue;
91 };
92 
93