1 /** @file
2 
3   A brief file description
4 
5   @section license License
6 
7   Licensed to the Apache Software Foundation (ASF) under one
8   or more contributor license agreements.  See the NOTICE file
9   distributed with this work for additional information
10   regarding copyright ownership.  The ASF licenses this file
11   to you under the Apache License, Version 2.0 (the
12   "License"); you may not use this file except in compliance
13   with the License.  You may obtain a copy of the License at
14 
15       http://www.apache.org/licenses/LICENSE-2.0
16 
17   Unless required by applicable law or agreed to in writing, software
18   distributed under the License is distributed on an "AS IS" BASIS,
19   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   See the License for the specific language governing permissions and
21   limitations under the License.
22  */
23 
24 /****************************************************************************
25 
26   P_UDPPacket.h
27   Implementation of UDPPacket
28 
29  ****************************************************************************/
30 
31 #pragma once
32 
33 #include "I_UDPNet.h"
34 
35 class UDPPacketInternal : public UDPPacket
36 {
37 public:
38   UDPPacketInternal();
39   ~UDPPacketInternal() override;
40 
41   void free() override;
42 
43   SLINK(UDPPacketInternal, alink); // atomic link
44   // packet scheduling stuff: keep it a doubly linked list
45   uint64_t pktLength = 0;
46 
47   int reqGenerationNum     = 0;
48   ink_hrtime delivery_time = 0; // when to deliver packet
49 
50   Ptr<IOBufferBlock> chain;
51   Continuation *cont          = nullptr; // callback on error
52   UDPConnectionInternal *conn = nullptr; // connection where packet should be sent to.
53 
54   int in_the_priority_queue = 0;
55   int in_heap               = 0;
56 };
57 
58 inkcoreapi extern ClassAllocator<UDPPacketInternal> udpPacketAllocator;
59 
60 TS_INLINE
UDPPacketInternal()61 UDPPacketInternal::UDPPacketInternal()
62 
63 {
64   memset(&from, '\0', sizeof(from));
65   memset(&to, '\0', sizeof(to));
66 }
67 
68 TS_INLINE
~UDPPacketInternal()69 UDPPacketInternal::~UDPPacketInternal()
70 {
71   chain = nullptr;
72 }
73 
74 TS_INLINE void
free()75 UDPPacketInternal::free()
76 {
77   chain = nullptr;
78   if (conn)
79     conn->Release();
80   conn = nullptr;
81   udpPacketAllocator.free(this);
82 }
83 
84 TS_INLINE void
append_block(IOBufferBlock * block)85 UDPPacket::append_block(IOBufferBlock *block)
86 {
87   UDPPacketInternal *p = static_cast<UDPPacketInternal *>(this);
88 
89   if (block) {
90     if (p->chain) { // append to end
91       IOBufferBlock *last = p->chain.get();
92       while (last->next) {
93         last = last->next.get();
94       }
95       last->next = block;
96     } else {
97       p->chain = block;
98     }
99   }
100 }
101 
102 TS_INLINE int64_t
getPktLength()103 UDPPacket::getPktLength() const
104 {
105   UDPPacketInternal *p = const_cast<UDPPacketInternal *>(static_cast<const UDPPacketInternal *>(this));
106   IOBufferBlock *b;
107 
108   p->pktLength = 0;
109   b            = p->chain.get();
110   while (b) {
111     p->pktLength += b->read_avail();
112     b = b->next.get();
113   }
114   return p->pktLength;
115 }
116 
117 TS_INLINE void
free()118 UDPPacket::free()
119 {
120   static_cast<UDPPacketInternal *>(this)->free();
121 }
122 
123 TS_INLINE void
setContinuation(Continuation * c)124 UDPPacket::setContinuation(Continuation *c)
125 {
126   static_cast<UDPPacketInternal *>(this)->cont = c;
127 }
128 
129 TS_INLINE void
setConnection(UDPConnection * c)130 UDPPacket::setConnection(UDPConnection *c)
131 {
132   /*Code reviewed by Case Larsen.  Previously, we just had
133      ink_assert(!conn).  This prevents tunneling of packets
134      correctly---that is, you get packets from a server on a udp
135      conn. and want to send it to a player on another connection, the
136      assert will prevent that.  The "if" clause enables correct
137      handling of the connection ref. counts in such a scenario. */
138 
139   UDPConnectionInternal *&conn = static_cast<UDPPacketInternal *>(this)->conn;
140 
141   if (conn) {
142     if (conn == c)
143       return;
144     conn->Release();
145     conn = nullptr;
146   }
147   conn = static_cast<UDPConnectionInternal *>(c);
148   conn->AddRef();
149 }
150 
151 TS_INLINE IOBufferBlock *
getIOBlockChain()152 UDPPacket::getIOBlockChain()
153 {
154   ink_assert(dynamic_cast<UDPPacketInternal *>(this) != nullptr);
155   return static_cast<UDPPacketInternal *>(this)->chain.get();
156 }
157 
158 TS_INLINE UDPConnection *
getConnection()159 UDPPacket::getConnection()
160 {
161   return static_cast<UDPPacketInternal *>(this)->conn;
162 }
163 
164 TS_INLINE UDPPacket *
new_UDPPacket(struct sockaddr const * to,ink_hrtime when,Ptr<IOBufferBlock> & buf)165 new_UDPPacket(struct sockaddr const *to, ink_hrtime when, Ptr<IOBufferBlock> &buf)
166 {
167   UDPPacketInternal *p = udpPacketAllocator.alloc();
168 
169   p->in_the_priority_queue = 0;
170   p->in_heap               = 0;
171   p->delivery_time         = when;
172   if (to)
173     ats_ip_copy(&p->to, to);
174   p->chain = buf;
175   return p;
176 }
177 
178 TS_INLINE UDPPacket *
new_incoming_UDPPacket(struct sockaddr * from,struct sockaddr * to,Ptr<IOBufferBlock> & block)179 new_incoming_UDPPacket(struct sockaddr *from, struct sockaddr *to, Ptr<IOBufferBlock> &block)
180 {
181   UDPPacketInternal *p = udpPacketAllocator.alloc();
182 
183   p->in_the_priority_queue = 0;
184   p->in_heap               = 0;
185   p->delivery_time         = 0;
186   ats_ip_copy(&p->from, from);
187   ats_ip_copy(&p->to, to);
188   p->chain = block;
189 
190   return p;
191 }
192 
193 TS_INLINE UDPPacket *
new_UDPPacket()194 new_UDPPacket()
195 {
196   UDPPacketInternal *p = udpPacketAllocator.alloc();
197   return p;
198 }
199