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 
27   This file implements an I/O Processor for network I/O on Unix.
28 
29 
30  ****************************************************************************/
31 
32 #pragma once
33 
34 #include "tscore/ink_sock.h"
35 #include "I_NetVConnection.h"
36 #include "P_UnixNetState.h"
37 #include "P_Connection.h"
38 #include "P_NetAccept.h"
39 #include "NetEvent.h"
40 
41 class UnixNetVConnection;
42 class NetHandler;
43 struct PollDescriptor;
44 
45 inline void
reset()46 NetVCOptions::reset()
47 {
48   ip_proto  = USE_TCP;
49   ip_family = AF_INET;
50   local_ip.invalidate();
51   local_port         = 0;
52   addr_binding       = ANY_ADDR;
53   f_blocking         = false;
54   f_blocking_connect = false;
55   socks_support      = NORMAL_SOCKS;
56   socks_version      = SOCKS_DEFAULT_VERSION;
57   socket_recv_bufsize =
58 #if defined(RECV_BUF_SIZE)
59     RECV_BUF_SIZE;
60 #else
61     0;
62 #endif
63   socket_send_bufsize = 0;
64   sockopt_flags       = 0;
65   packet_mark         = 0;
66   packet_tos          = 0;
67 
68   etype = ET_NET;
69 
70   sni_servername              = nullptr;
71   ssl_servername              = nullptr;
72   sni_hostname                = nullptr;
73   ssl_client_cert_name        = nullptr;
74   ssl_client_private_key_name = nullptr;
75 }
76 
77 inline void
set_sock_param(int _recv_bufsize,int _send_bufsize,unsigned long _opt_flags,unsigned long _packet_mark,unsigned long _packet_tos)78 NetVCOptions::set_sock_param(int _recv_bufsize, int _send_bufsize, unsigned long _opt_flags, unsigned long _packet_mark,
79                              unsigned long _packet_tos)
80 {
81   socket_recv_bufsize = _recv_bufsize;
82   socket_send_bufsize = _send_bufsize;
83   sockopt_flags       = _opt_flags;
84   packet_mark         = _packet_mark;
85   packet_tos          = _packet_tos;
86 }
87 
88 struct OOB_callback : public Continuation {
89   char *data;
90   int length;
91   Event *trigger;
92   UnixNetVConnection *server_vc;
93   Continuation *server_cont;
94   int retry_OOB_send(int, Event *);
95 
OOB_callbackOOB_callback96   OOB_callback(Ptr<ProxyMutex> &m, NetVConnection *vc, Continuation *cont, char *buf, int len)
97     : Continuation(m), data(buf), length(len), trigger(nullptr)
98   {
99     server_vc   = (UnixNetVConnection *)vc;
100     server_cont = cont;
101     SET_HANDLER(&OOB_callback::retry_OOB_send);
102   }
103 };
104 
105 enum tcp_congestion_control_t { CLIENT_SIDE, SERVER_SIDE };
106 
107 class UnixNetVConnection : public NetVConnection, public NetEvent
108 {
109 public:
110   VIO *do_io_read(Continuation *c, int64_t nbytes, MIOBuffer *buf) override;
111   VIO *do_io_write(Continuation *c, int64_t nbytes, IOBufferReader *buf, bool owner = false) override;
112 
113   Continuation *read_vio_cont() override;
114   Continuation *write_vio_cont() override;
115 
116   bool get_data(int id, void *data) override;
117 
118   Action *send_OOB(Continuation *cont, char *buf, int len) override;
119   void cancel_OOB() override;
120 
121   const char *
get_server_name()122   get_server_name() const override
123   {
124     return nullptr;
125   }
126 
127   void do_io_close(int lerrno = -1) override;
128   void do_io_shutdown(ShutdownHowTo_t howto) override;
129 
130   ////////////////////////////////////////////////////////////
131   // Set the timeouts associated with this connection.      //
132   // active_timeout is for the total elapsed time of        //
133   // the connection.                                        //
134   // inactivity_timeout is the elapsed time from the time   //
135   // a read or a write was scheduled during which the       //
136   // connection  was unable to sink/provide data.           //
137   // calling these functions repeatedly resets the timeout. //
138   // These functions are NOT THREAD-SAFE, and may only be   //
139   // called when handing an  event from this NetVConnection,//
140   // or the NetVConnection creation callback.               //
141   ////////////////////////////////////////////////////////////
142   virtual void set_active_timeout(ink_hrtime timeout_in) override;
143   virtual void set_inactivity_timeout(ink_hrtime timeout_in) override;
144   virtual void set_default_inactivity_timeout(ink_hrtime timeout_in) override;
145   virtual bool is_default_inactivity_timeout() override;
146   virtual void cancel_active_timeout() override;
147   virtual void cancel_inactivity_timeout() override;
148   void set_action(Continuation *c) override;
149   const Action *get_action() const;
150   virtual void add_to_keep_alive_queue() override;
151   virtual void remove_from_keep_alive_queue() override;
152   virtual bool add_to_active_queue() override;
153   virtual void remove_from_active_queue();
154 
155   // The public interface is VIO::reenable()
156   void reenable(VIO *vio) override;
157   void reenable_re(VIO *vio) override;
158 
159   SOCKET get_socket() override;
160 
161   ~UnixNetVConnection() override;
162 
163   /////////////////////////////////////////////////////////////////
164   // instances of UnixNetVConnection should be allocated         //
165   // only from the free list using UnixNetVConnection::alloc().  //
166   // The constructor is public just to avoid compile errors.      //
167   /////////////////////////////////////////////////////////////////
168   UnixNetVConnection();
169 
170   int populate_protocol(std::string_view *results, int n) const override;
171   const char *protocol_contains(std::string_view tag) const override;
172 
173   // noncopyable
174   UnixNetVConnection(const NetVConnection &) = delete;
175   UnixNetVConnection &operator=(const NetVConnection &) = delete;
176 
177   /////////////////////////
178   // UNIX implementation //
179   /////////////////////////
180   void set_enabled(VIO *vio);
181 
182   void get_local_sa();
183 
184   // these are not part of the pure virtual interface.  They were
185   // added to reduce the amount of duplicate code in classes inherited
186   // from NetVConnection (SSL).
187   virtual int
sslStartHandShake(int event,int & err)188   sslStartHandShake(int event, int &err)
189   {
190     (void)event;
191     (void)err;
192     return EVENT_ERROR;
193   }
194 
195   virtual bool
getSSLHandShakeComplete()196   getSSLHandShakeComplete() const
197   {
198     return (true);
199   }
200 
201   virtual bool
trackFirstHandshake()202   trackFirstHandshake()
203   {
204     return false;
205   }
206 
207   // NetEvent
208   virtual void net_read_io(NetHandler *nh, EThread *lthread) override;
209   virtual void net_write_io(NetHandler *nh, EThread *lthread) override;
210   virtual void free(EThread *t) override;
211   virtual int
close()212   close() override
213   {
214     return this->con.close();
215   }
216   virtual int
get_fd()217   get_fd() override
218   {
219     return this->con.fd;
220   }
221 
222   virtual EThread *
get_thread()223   get_thread() override
224   {
225     return this->thread;
226   }
227 
228   virtual int
229   callback(int event = CONTINUATION_EVENT_NONE, void *data = nullptr) override
230   {
231     return this->handleEvent(event, data);
232   }
233 
234   virtual Ptr<ProxyMutex> &
get_mutex()235   get_mutex() override
236   {
237     return this->mutex;
238   }
239 
240   virtual ContFlags &
get_control_flags()241   get_control_flags() override
242   {
243     return this->control_flags;
244   }
245 
246   virtual int64_t load_buffer_and_write(int64_t towrite, MIOBufferAccessor &buf, int64_t &total_written, int &needs);
247   void readDisable(NetHandler *nh);
248   void readSignalError(NetHandler *nh, int err);
249   int readSignalDone(int event, NetHandler *nh);
250   int readSignalAndUpdate(int event);
251   void readReschedule(NetHandler *nh);
252   void writeReschedule(NetHandler *nh);
253   void netActivity(EThread *lthread);
254   /**
255    * If the current object's thread does not match the t argument, create a new
256    * NetVC in the thread t context based on the socket and ssl information in the
257    * current NetVC and mark the current NetVC to be closed.
258    */
259   UnixNetVConnection *migrateToCurrentThread(Continuation *c, EThread *t);
260 
261   Action action_;
262 
263   unsigned int id = 0;
264 
265   Connection con;
266   int recursion            = 0;
267   OOB_callback *oob_ptr    = nullptr;
268   bool from_accept_thread  = false;
269   NetAccept *accept_object = nullptr;
270 
271   int startEvent(int event, Event *e);
272   int acceptEvent(int event, Event *e);
273   int mainEvent(int event, Event *e);
274   virtual int connectUp(EThread *t, int fd);
275   /**
276    * Populate the current object based on the socket information in in the
277    * con parameter.
278    * This is logic is invoked when the NetVC object is created in a new thread context
279    */
280   virtual int populate(Connection &con, Continuation *c, void *arg);
281   virtual void clear();
282 
283   ink_hrtime get_inactivity_timeout() override;
284   ink_hrtime get_active_timeout() override;
285 
286   virtual void set_local_addr() override;
287   void set_mptcp_state() override;
288   virtual void set_remote_addr() override;
289   void set_remote_addr(const sockaddr *) override;
290   int set_tcp_congestion_control(int side) override;
291   void apply_options() override;
292 
293   friend void write_to_net_io(NetHandler *, UnixNetVConnection *, EThread *);
294 
295 private:
296   virtual void *_prepareForMigration();
297   virtual NetProcessor *_getNetProcessor();
298 };
299 
300 extern ClassAllocator<UnixNetVConnection> netVCAllocator;
301 
302 typedef int (UnixNetVConnection::*NetVConnHandler)(int, void *);
303 
304 inline void
set_remote_addr()305 UnixNetVConnection::set_remote_addr()
306 {
307   ats_ip_copy(&remote_addr, &con.addr);
308   this->control_flags.set_flag(ContFlags::DEBUG_OVERRIDE, diags->test_override_ip(remote_addr));
309 }
310 
311 inline void
set_remote_addr(const sockaddr * new_sa)312 UnixNetVConnection::set_remote_addr(const sockaddr *new_sa)
313 {
314   ats_ip_copy(&remote_addr, new_sa);
315   this->control_flags.set_flag(ContFlags::DEBUG_OVERRIDE, diags->test_override_ip(remote_addr));
316 }
317 
318 inline void
set_local_addr()319 UnixNetVConnection::set_local_addr()
320 {
321   int local_sa_size = sizeof(local_addr);
322   // This call will fail if fd is closed already. That is ok, because the
323   // `local_addr` is checked within get_local_addr() and the `got_local_addr`
324   // is set only with a valid `local_addr`.
325   ATS_UNUSED_RETURN(safe_getsockname(con.fd, &local_addr.sa, &local_sa_size));
326 }
327 
328 // Update the internal VC state variable for MPTCP
329 inline void
set_mptcp_state()330 UnixNetVConnection::set_mptcp_state()
331 {
332   int mptcp_enabled      = -1;
333   int mptcp_enabled_size = sizeof(mptcp_enabled);
334 
335   if (0 == safe_getsockopt(con.fd, IPPROTO_TCP, MPTCP_ENABLED, (char *)&mptcp_enabled, &mptcp_enabled_size)) {
336     Debug("socket_mptcp", "MPTCP socket state: %d", mptcp_enabled);
337     mptcp_state = mptcp_enabled > 0 ? true : false;
338   } else {
339     Debug("socket_mptcp", "MPTCP failed getsockopt(): %s", strerror(errno));
340   }
341 }
342 
343 inline ink_hrtime
get_active_timeout()344 UnixNetVConnection::get_active_timeout()
345 {
346   return active_timeout_in;
347 }
348 
349 inline ink_hrtime
get_inactivity_timeout()350 UnixNetVConnection::get_inactivity_timeout()
351 {
352   return inactivity_timeout_in;
353 }
354 
355 inline void
set_active_timeout(ink_hrtime timeout_in)356 UnixNetVConnection::set_active_timeout(ink_hrtime timeout_in)
357 {
358   Debug("socket", "Set active timeout=%" PRId64 ", NetVC=%p", timeout_in, this);
359   active_timeout_in        = timeout_in;
360   next_activity_timeout_at = (active_timeout_in > 0) ? Thread::get_hrtime() + timeout_in : 0;
361 }
362 
363 inline void
cancel_inactivity_timeout()364 UnixNetVConnection::cancel_inactivity_timeout()
365 {
366   Debug("socket", "Cancel inactive timeout for NetVC=%p", this);
367   inactivity_timeout_in      = 0;
368   next_inactivity_timeout_at = 0;
369 }
370 
371 inline void
cancel_active_timeout()372 UnixNetVConnection::cancel_active_timeout()
373 {
374   Debug("socket", "Cancel active timeout for NetVC=%p", this);
375   active_timeout_in        = 0;
376   next_activity_timeout_at = 0;
377 }
378 
~UnixNetVConnection()379 inline UnixNetVConnection::~UnixNetVConnection() {}
380 
381 inline SOCKET
get_socket()382 UnixNetVConnection::get_socket()
383 {
384   return con.fd;
385 }
386 
387 inline void
set_action(Continuation * c)388 UnixNetVConnection::set_action(Continuation *c)
389 {
390   action_ = c;
391 }
392 
393 inline const Action *
get_action()394 UnixNetVConnection::get_action() const
395 {
396   return &action_;
397 }
398 
399 // declarations for local use (within the net module)
400 
401 void write_to_net(NetHandler *nh, UnixNetVConnection *vc, EThread *thread);
402 void write_to_net_io(NetHandler *nh, UnixNetVConnection *vc, EThread *thread);
403 void net_activity(UnixNetVConnection *vc, EThread *thread);
404