XRootD
Loading...
Searching...
No Matches
XrdNetMsg.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d N e t M s g . c c */
4/* */
5/* (c) 2007 by the Board of Trustees of the Leland Stanford, Jr., University */
6/* All Rights Reserved */
7/* Produced by Andrew Hanushevsky for Stanford University under contract */
8/* DE-AC02-76-SFO0515 with the Department of Energy */
9/* */
10/* This file is part of the XRootD software suite. */
11/* */
12/* XRootD is free software: you can redistribute it and/or modify it under */
13/* the terms of the GNU Lesser General Public License as published by the */
14/* Free Software Foundation, either version 3 of the License, or (at your */
15/* option) any later version. */
16/* */
17/* XRootD is distributed in the hope that it will be useful, but WITHOUT */
18/* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
19/* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
20/* License for more details. */
21/* */
22/* You should have received a copy of the GNU Lesser General Public License */
23/* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
24/* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
25/* */
26/* The copyright holder's institutional names and contributor's names may not */
27/* be used to endorse or promote products derived from this software without */
28/* specific prior written permission of the institution or contributor. */
29/******************************************************************************/
30
31#include <cerrno>
32#include <poll.h>
33#include <sys/uio.h>
34
35#include "XrdNet/XrdNet.hh"
36#include "XrdNet/XrdNetMsg.hh"
37#include "XrdNet/XrdNetOpts.hh"
38#include "XrdNet/XrdNetPeer.hh"
40#include "XrdSys/XrdSysError.hh"
42
43namespace
44{
45// Some systems, such as macOS, send a UDP datagram only when it fits the send
46// buffer of its socket. XrdNet sets the buffer to XRDNET_UDPBUFFSZ (32 KiB),
47// so make it large enough for the largest UDP payload. Never make it smaller.
48//
49void FitDatagram(int fd)
50{
51 const int minSize = 65536;
52 int curSize = 0;
53 SOCKLEN_t szLen = sizeof(curSize);
54
55 if (fd < 0) return;
56 if (!getsockopt(fd, SOL_SOCKET, SO_SNDBUF, (Sokdata_t)&curSize, &szLen)
57 && curSize >= minSize) return;
58 setsockopt(fd, SOL_SOCKET, SO_SNDBUF, (Sokdata_t)&minSize, sizeof(minSize));
59}
60}
61
62/******************************************************************************/
63/* C o n s t r u c t o r */
64/******************************************************************************/
65
66XrdNetMsg::XrdNetMsg(XrdSysError *erp, const char *dest, bool *aOK, bool refr)
67 : eDest(erp)
68{
69 XrdNet myNet(erp);
70 bool aok = true;
71
72// Handle the case where no dest was specified. In this case we will always
73// need the caller to specify a destination.
74//
75 if (!dest)
76 {if ((FD = myNet.Relay(dest)) < 0)
77 {eDest->Emsg("NetMsg", "Unable to create UDP msg socket.");
78 aok = false;
79 } else FitDatagram(FD);
80 if (aOK) *aOK = aok;
81 return;
82 }
83
84// Hande the common case where a dest is specified. We first make
85// sure the dest is valid, eventhough that will occur again, so we van
86// generate a resonable error message.
87//
88 XrdNetAddr specDest;
89 const char *eText = specDest.Set(dest);
90 if (eText)
91 {eDest->Emsg("NetMsg", "Default", dest, "is unreachable");
92 if (aOK) *aOK = false;
93 return;
94 }
95
96// Obtain a file description for this socket and set the endpoint address
97//
98 XrdNetPeer myPeer;
99
100 if (!myNet.Relay(myPeer, dest, XRDNET_SENDONLY))
101 {eDest->Emsg("NetMsg", "Unable to create UDP msg socket.");
102 if (aOK) *aOK = false;
103 return;
104 }
105
106// Save the relevant information
107//
108 dfltDest = strdup(myPeer.InetName ? myPeer.InetName : "Unknown!");
109 FD = myPeer.fd;
110 destOK = true;
111 FitDatagram(FD);
112
113// If address refresh wanted, register this socket for refresh. This should
114// never fail and if it does we return non-success.
115//
116 if (refr && !XrdNetRefresh::Register(myPeer)) aok = false;
117
118// All done
119//
120 if (aOK) *aOK = aok;
121}
122
123/******************************************************************************/
124/* D e s t r u c t o r */
125/******************************************************************************/
126
128{
129// If we are registered,deregister
130//
132
133// Close the socket
134//
135 if (close(FD) < 0)
136 eDest->Emsg("NetMsg", errno, "close socket for", dfltDest);
137
138// Free the poiinter to the default dest
139//
140 free(dfltDest);
141}
142
143/******************************************************************************/
144/* S e n d */
145/******************************************************************************/
146
147int XrdNetMsg::Send(const char *Buff, int Blen, const char *dest, int tmo)
148{
149 int retc;
150
151// Get the buffer length of not specified
152//
153 if (!Blen && !(Blen = strlen(Buff))) return 0;
154
155// Handle the case where we are sendingto he dest setup at construction. This
156// is the most common case.
157//
158 if (!dest)
159 {if (!destOK)
160 {eDest->Emsg("NetMsg", "Destination not specified."); return -1;}
161
162 if (tmo >= 0 && !OK2Send(tmo, dfltDest)) return 1;
163
164 do {retc = send(FD, (Sokdata_t)Buff, Blen, 0);
165 } while (retc < 0 && errno == EINTR);
166
167 return (retc < 0 ? retErr(errno, dfltDest) : 0);
168 }
169
170// Caller want to send to a specific destination other than the default
171//
172 XrdNetAddr specDest;
173
174 if (specDest.Set(dest))
175 {eDest->Emsg("NetMsg", dest, "is unreachable"); return -1;}
176
177 if (tmo >= 0 && !OK2Send(tmo, dest)) return 1;
178
179 do {retc = sendto(FD, (Sokdata_t)Buff, Blen, 0,
180 specDest.SockAddr(), specDest.SockSize());}
181 while (retc < 0 && errno == EINTR);
182
183 return (retc < 0 ? retErr(errno, specDest) : 0);
184}
185
186/******************************************************************************/
187
188int XrdNetMsg::Send(const char *dest, const XrdNetSockAddr &netSA,
189 const char *Buff, int Blen, int tmo)
190{
191 int aSize, retc;
192
193 if (!Blen && !(Blen = strlen(Buff))) return 0;
194
195 if (netSA.Addr.sa_family == AF_INET) aSize = sizeof(netSA.v4);
196 else if (netSA.Addr.sa_family == AF_INET6) aSize = sizeof(netSA.v6);
197 else return retErr(EAFNOSUPPORT, (dest ? dest : "Unknown!"));
198
199 if (tmo >= 0 && !OK2Send(tmo, dest)) return 1;
200
201 do {retc = sendto(FD, (Sokdata_t)Buff, Blen, 0, &netSA.Addr, aSize);}
202 while (retc < 0 && errno == EINTR);
203
204 if (retc >= 0) return 0;
205 return retErr(errno, (dest ? dest : "Unknown!"));
206}
207
208/******************************************************************************/
209
210int XrdNetMsg::Send(const struct iovec iov[], int iovcnt,
211 const char *dest, int tmo)
212{
213
214// Handle the common case of sendingto the cobbected address
215//
216 if (!dest)
217 {if (!destOK)
218 {eDest->Emsg("NetMsg", "Destination not specified."); return -1;}
219 if (tmo >= 0 && !OK2Send(tmo, dfltDest)) return 1;
220 if (writev(FD, iov, iovcnt) >= 0) return 0;
221 return retErr(errno, dfltDest);
222 }
223
224// Caller want to send to a specific destination other than the default
225//
226 XrdNetAddr specDest;
227 int retc;
228
229 if (specDest.Set(dest))
230 {eDest->Emsg("NetMsg", dest, "is unreachable"); return -1;}
231
232// Create the message via the msghdr
233//
234 struct msghdr mHdr{};
235
236 mHdr.msg_name = (void*)specDest.SockAddr();
237 mHdr.msg_namelen = specDest.SockSize();
238 mHdr.msg_iov = const_cast<struct iovec*>(iov);
239 mHdr.msg_iovlen = iovcnt;
240
241// Handle timeout if need be
242//
243 if (tmo >= 0 && !OK2Send(tmo, dest)) return 1;
244
245// Send the message
246//
247 do {retc = sendmsg(FD, &mHdr, 0);} while (retc < 0 && errno == EINTR);
248
249// All done
250//
251 return (retc < 0 ? retErr(errno, specDest) : 0);
252}
253
254/******************************************************************************/
255/* P r i v a t e M e t h o d s */
256/******************************************************************************/
257/******************************************************************************/
258/* O K 2 S e n d */
259/******************************************************************************/
260
261int XrdNetMsg::OK2Send(int timeout, const char *dest)
262{
263 struct pollfd polltab = {FD, POLLOUT|POLLWRNORM, 0};
264 int retc;
265
266 do {retc = poll(&polltab, 1, timeout);} while(retc < 0 && errno == EINTR);
267
268 if (retc == 0 || !(polltab.revents & (POLLOUT | POLLWRNORM)))
269 eDest->Emsg("NetMsg", "UDP link to", dest, "is blocked.");
270 else if (retc < 0)
271 eDest->Emsg("NetMsg",errno,"poll", dest);
272 else return 1;
273 return 0;
274}
275
276/******************************************************************************/
277/* r e t E r r */
278/******************************************************************************/
279
280int XrdNetMsg::retErr(int ecode, const char *theDest)
281{
282 if (!theDest)
283 {if (!destOK)
284 {eDest->Emsg("NetMsg", "Destination not specified."); return -1;}
285 theDest = dfltDest;
286 }
287 eDest->Emsg("NetMsg", ecode, "send to", theDest);
288 return (EWOULDBLOCK == ecode || EAGAIN == ecode ? 1 : -1);
289}
290
291int XrdNetMsg::retErr(int ecode, XrdNetAddr& theDest)
292{
293 return retErr(ecode, theDest.Name("unknown"));
294}
#define XRDNET_SENDONLY
Definition XrdNetOpts.hh:43
struct sockaddr_in6 v6
struct sockaddr Addr
struct sockaddr_in v4
#define close(a)
Definition XrdPosix.hh:48
#define writev(a, b, c)
Definition XrdPosix.hh:123
#define SOCKLEN_t
#define Sokdata_t
const sockaddr * SockAddr()
SOCKLEN_t SockSize()
const char * Name(const char *eName=0, const char **eText=0)
const char * Set(const char *hSpec, int pNum=PortInSpec)
int retErr(int ecode, const char *theDest)
Definition XrdNetMsg.cc:280
int Send(const char *buff, int blen=0, const char *dest=0, int tmo=-1)
Definition XrdNetMsg.cc:147
XrdNetMsg(XrdSysError *erp, const char *dest=0, bool *aOK=0, bool refr=false)
Definition XrdNetMsg.cc:66
XrdSysError * eDest
Definition XrdNetMsg.hh:145
int OK2Send(int timeout, const char *dest)
Definition XrdNetMsg.cc:261
~XrdNetMsg()
Destructor.
Definition XrdNetMsg.cc:127
bool destOK
Definition XrdNetMsg.hh:148
bool isRefr
Definition XrdNetMsg.hh:149
char * dfltDest
Definition XrdNetMsg.hh:146
char * InetName
Definition XrdNetPeer.hh:44
static bool Register(XrdNetPeer &Peer)
static void UnRegister(int fd)
int Relay(XrdNetPeer &Peer, const char *dest, int opts=0)
Definition XrdNet.cc:313