XRootD
XrdNet.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d N e t . c c */
4 /* */
5 /* (c) 2004 by the Board of Trustees of the Leland Stanford, Jr., University */
6 /* Produced by Andrew Hanushevsky for Stanford University under contract */
7 /* DE-AC02-76-SFO0515 with the Department of Energy */
8 /* */
9 /* This file is part of the XRootD software suite. */
10 /* */
11 /* XRootD is free software: you can redistribute it and/or modify it under */
12 /* the terms of the GNU Lesser General Public License as published by the */
13 /* Free Software Foundation, either version 3 of the License, or (at your */
14 /* option) any later version. */
15 /* */
16 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
17 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
18 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
19 /* License for more details. */
20 /* */
21 /* You should have received a copy of the GNU Lesser General Public License */
22 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
23 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
24 /* */
25 /* The copyright holder's institutional names and contributor's names may not */
26 /* be used to endorse or promote products derived from this software without */
27 /* specific prior written permission of the institution or contributor. */
28 /******************************************************************************/
29 
30 #include <cerrno>
31 #include <fcntl.h>
32 #include <cstdio>
33 #include <cstring>
34 #ifndef WIN32
35 #include <poll.h>
36 #include <unistd.h>
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #else
40 #include "XrdSys/XrdWin32.hh"
41 #endif
42 
43 #include "XrdNet/XrdNet.hh"
44 #include "XrdNet/XrdNetAddr.hh"
45 #include "XrdNet/XrdNetBuffer.hh"
46 #include "XrdNet/XrdNetOpts.hh"
47 #include "XrdNet/XrdNetPeer.hh"
48 #include "XrdNet/XrdNetSecurity.hh"
49 #include "XrdNet/XrdNetSocket.hh"
50 #include "XrdNet/XrdNetUtils.hh"
51 
52 #include "XrdSys/XrdSysPlatform.hh"
53 #include "XrdSys/XrdSysError.hh"
54 #include "XrdSys/XrdSysFD.hh"
55 
56 /******************************************************************************/
57 /* C o n s t r u c t o r */
58 /******************************************************************************/
59 
61 {
62  iofd = PortType = -1;
63  eDest = erp;
64  Police = secp;
65  Domlen = Portnum = Windowsz = netOpts = 0;
66  Domain = 0;
67  BuffQ = 0;
68 }
69 
70 /******************************************************************************/
71 /* D e s t r u c t o r */
72 /******************************************************************************/
73 
75 {
76  unBind();
77  if (Domain) free(Domain);
78 }
79 
80 /******************************************************************************/
81 /* A c c e p t */
82 /******************************************************************************/
83 
84 int XrdNet::Accept(XrdNetAddr &myAddr, int opts, int timeout)
85 {
86  int retc;
87 
88 // Make sure we are bound to a port
89 //
90  opts |= netOpts;
91  if (iofd < 0)
92  {if (!(opts & XRDNET_NOEMSG))
93  eDest->Emsg("Accept", "Network not bound to a port.");
94  return 0;
95  }
96 
97 // This interface only accepts TCP connections
98 //
99  if (PortType != SOCK_STREAM)
100  {if (!(opts & XRDNET_NOEMSG))
101  eDest->Emsg("Accept", "UDP network not supported for NetAddr call.");
102  return 0;
103  }
104 
105 // Setup up the poll structure to wait for new connections
106 //
107  do {if (timeout >= 0)
108  {struct pollfd sfd = {iofd,
109  POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI|POLLHUP,0};
110  do {retc = poll(&sfd, 1, timeout*1000);}
111  while(retc < 0 && (errno == EAGAIN || errno == EINTR));
112  if (!retc)
113  {if (!(opts & XRDNET_NOEMSG))
114  eDest->Emsg("Accept", "Accept timed out.");
115  return 0;
116  }
117  }
118  } while(!do_Accept_TCP(myAddr, opts));
119 
120  return 1;
121 }
122 
123 /******************************************************************************/
124 
125 int XrdNet::Accept(XrdNetPeer &myPeer, int opts, int timeout)
126 {
127  int retc;
128 
129 // Make sure we are bound to a port
130 //
131  opts |= netOpts;
132  if (iofd < 0)
133  {if (!(opts & XRDNET_NOEMSG))
134  eDest->Emsg("Accept", "Network not bound to a port.");
135  return 0;
136  }
137 
138 // Setup up the poll structure to wait for new connections
139 //
140  do {if (timeout >= 0)
141  {struct pollfd sfd = {iofd,
142  POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI|POLLHUP,0};
143  do {retc = poll(&sfd, 1, timeout*1000);}
144  while(retc < 0 && (errno == EAGAIN || errno == EINTR));
145  if (!retc)
146  {if (!(opts & XRDNET_NOEMSG))
147  eDest->Emsg("Accept", "Accept timed out.");
148  return 0;
149  }
150  }
151  } while(!(PortType == SOCK_STREAM ? do_Accept_TCP(myPeer, opts)
152  : do_Accept_UDP(myPeer, opts)));
153 
154 // Accept completed, trim the host name if a domain has been specified,
155 //
156  if (Domain && !(opts & XRDNET_NODNTRIM)) Trim(myPeer.InetName);
157  return 1;
158 }
159 
160 /******************************************************************************/
161 /* B i n d */
162 /******************************************************************************/
163 
164 int XrdNet::Bind(int bindport, const char *contype)
165 {
166  XrdNetSocket mySocket(eDest);
167  int opts = XRDNET_SERVER | netOpts;
168  int buffsz = Windowsz;
169 
170 // Close any open socket here
171 //
172  unBind();
173 
174 // Get correct option settings
175 //
176  if (*contype != 'u') PortType = SOCK_STREAM;
177  else {PortType = SOCK_DGRAM;
179  if (!buffsz) buffsz = XRDNET_UDPBUFFSZ;
180  }
181 
182 // Try to open and bind to this port
183 //
184  if (mySocket.Open(0, bindport, opts, buffsz) < 0)
185  return -mySocket.LastError();
186 
187 // Success, get the socket number and return
188 //
189  iofd = mySocket.Detach();
190 
191 // Obtain port number of generic port being used
192 //
193  Portnum = (bindport ? bindport : XrdNetUtils::Port(iofd));
194 
195 // For udp sockets, we must allocate a buffer queue object
196 //
197  if (PortType == SOCK_DGRAM)
198  {BuffSize = buffsz;
199  BuffQ = new XrdNetBufferQ(buffsz);
200  }
201  return 0;
202 }
203 
204 /******************************************************************************/
205 
206 int XrdNet::Bind(char *path, const char *contype)
207 {
208  XrdNetSocket mySocket(eDest);
209  int opts = XRDNET_SERVER | netOpts;
210  int buffsz = Windowsz;
211 
212 // Make sure this is a path and not a host name
213 //
214  if (*path != '/')
215  {eDest->Emsg("Bind", "Invalid bind path -", path);
216  return -EINVAL;
217  }
218 
219 // Close any open socket here
220 //
221  unBind();
222 
223 // Get correct option settings
224 //
225  if (*contype != 'd') PortType = SOCK_STREAM;
226  else {PortType = SOCK_DGRAM;
228  if (!buffsz) buffsz = XRDNET_UDPBUFFSZ;
229  }
230 
231 // Try to open and bind to this path
232 //
233  if (mySocket.Open(path, -1, opts, buffsz) < 0) return -mySocket.LastError();
234 
235 // Success, get the socket number and return
236 //
237  iofd = mySocket.Detach();
238 
239 // For udp sockets, we must allocate a buffer queue object
240 //
241  if (PortType == SOCK_DGRAM)
242  {BuffSize = buffsz;
243  BuffQ = new XrdNetBufferQ(buffsz);
244  }
245  return 0;
246 }
247 
248 /******************************************************************************/
249 /* C o n n e c t */
250 /******************************************************************************/
251 
252 int XrdNet::Connect(XrdNetAddr &myAddr, const char *host,
253  int port, int opts, int tmo)
254 {
255  XrdNetSocket mySocket(opts & XRDNET_NOEMSG ? 0 : eDest);
256 
257 // Determine appropriate options but turn off UDP sockets
258 //
260  if (tmo > 0) opts = (opts & ~XRDNET_TOUT) | (tmo > 255 ? 255 : tmo);
261 
262 // Now perform the connect and return the results if successful
263 //
264  if (mySocket.Open(host, port, opts, Windowsz) < 0) return 0;
265  myAddr.Set(mySocket.Detach());
266  if (!(opts & XRDNET_NORLKUP)) myAddr.Name();
267  return 1;
268 }
269 
270 /******************************************************************************/
271 
273  const char *host, int port, int opts, int tmo)
274 {
275  XrdNetSocket mySocket(opts & XRDNET_NOEMSG ? 0 : eDest);
276  const struct sockaddr *sap;
277  int buffsz = Windowsz;
278 
279 // Determine appropriate options
280 //
281  opts |= netOpts;
282  if ((opts & XRDNET_UDPSOCKET) && !buffsz) buffsz = XRDNET_UDPBUFFSZ;
283  if (tmo > 0) opts = (opts & ~XRDNET_TOUT) | (tmo > 255 ? 255 : tmo);
284 
285 // Now perform the connect and return the peer structure if successful
286 //
287  if (mySocket.Open(host, port, opts, buffsz) < 0) return 0;
288  if (myPeer.InetName) free(myPeer.InetName);
289  if ((opts & XRDNET_UDPSOCKET) || !host)
290  {myPeer.InetName = strdup("n/a");
291  memset((void *)&myPeer.Inet, 0, sizeof(myPeer.Inet));
292  } else {
293  const char *pn = mySocket.Peername(&sap);
294  if (pn) {memcpy((void *)&myPeer.Inet, sap, sizeof(myPeer.Inet));
295  myPeer.InetName = strdup(pn);
296  if (Domain && !(opts & XRDNET_NODNTRIM)) Trim(myPeer.InetName);
297  } else {
298  memset((void *)&myPeer.Inet, 0, sizeof(myPeer.Inet));
299  myPeer.InetName = strdup("unknown");
300  }
301  }
302  myPeer.fd = mySocket.Detach();
303  return 1;
304 }
305 
306 /******************************************************************************/
307 /* R e l a y */
308 /******************************************************************************/
309 
310 int XrdNet::Relay(XrdNetPeer &Peer, const char *dest, int opts)
311 {
312  return Connect(Peer, dest, -1, opts | XRDNET_UDPSOCKET);
313 }
314 
315 /******************************************************************************/
316 
317 int XrdNet::Relay(const char *dest)
318 {
319  XrdNetPeer myPeer;
320 
321  return (Connect(myPeer, dest, -1, XRDNET_UDPSOCKET | XRDNET_SENDONLY)
322  ? myPeer.fd : -1);
323 }
324 
325 /******************************************************************************/
326 /* S e c u r e */
327 /******************************************************************************/
328 
330 {
331 
332 // If we don't have a Police object then use the one supplied. Otherwise
333 // merge the supplied object into the existing object.
334 //
335  if (Police) Police->Merge(secp);
336  else Police = secp;
337 }
338 
339 /******************************************************************************/
340 /* T r i m */
341 /******************************************************************************/
342 
343 void XrdNet::Trim(char *hname)
344 {
345  int k = strlen(hname);
346  char *hnp;
347 
348  if (Domlen && k > Domlen)
349  {hnp = hname + (k - Domlen);
350  if (!strcmp(Domain, hnp)) *hnp = '\0';
351  }
352 }
353 
354 /******************************************************************************/
355 /* u n B i n d */
356 /******************************************************************************/
357 
359 {
360  if (iofd >= 0) {close(iofd); iofd=-1; Portnum=0;}
361  if (BuffQ) {delete BuffQ; BuffQ = 0;}
362 }
363 
364 /******************************************************************************/
365 /* W S i z e */
366 /******************************************************************************/
367 
369 {
370  int wsz;
371 
372  if (iofd >= 0 && !XrdNetSocket::getWindow(iofd, wsz, eDest)) return wsz;
373  return 0;
374 }
375 
376 /******************************************************************************/
377 /* P r i v a t e M e t h o d s */
378 /******************************************************************************/
379 /******************************************************************************/
380 /* d o _ A c c e p t _ T C P */
381 /******************************************************************************/
382 
383 int XrdNet::do_Accept_TCP(XrdNetAddr &hAddr, int opts)
384 {
385  static int noAcpt = 0;
386  XrdNetSockAddr IP;
387  SOCKLEN_t addrlen = sizeof(IP);
388  int newfd;
389 
390 // Remove UDP option if present
391 //
393 
394 // Accept a connection
395 //
396  do {newfd = XrdSysFD_Accept(iofd, &IP.Addr, &addrlen);}
397  while(newfd < 0 && errno == EINTR);
398 
399  if (newfd < 0)
400  {if (!(opts & XRDNET_NOEMSG) && (errno != EMFILE || !(0x1ff & noAcpt++)))
401  eDest->Emsg("Accept", errno, "perform accept");
402  return 0;
403  }
404 
405 // Initialize the address of the new connection
406 //
407  const char *eMsg = hAddr.Set(&IP.Addr, newfd);
408  if (eMsg)
409  {char buff[256];
410  snprintf(buff, sizeof(buff), "%d;", newfd);
411  eDest->Emsg("Accept", "Failed to identify FD", buff, eMsg);
412  close(newfd);
413  return 0;
414  }
415 
416 // Remove TCP_NODELAY option for unix domain sockets to avoid error message
417 //
419 
420 // Set all required fd options are set
421 //
423 
424 // Authorize by ip address or full (slow) hostname format
425 //
426  if (Police)
427  {if (!Police->Authorize(hAddr))
428  {char ipbuff[512];
429  hAddr.Format(ipbuff, sizeof(ipbuff),
433  eDest->Emsg("Accept",EACCES,"accept TCP connection from",ipbuff);
434  close(newfd);
435  return 0;
436  }
437  }
438 
439 // Force resolution of the addres unless reverse lookup not desired
440 //
441  if (!(opts & XRDNET_NORLKUP)) hAddr.Name();
442 
443 // All done
444 //
445  return 1;
446 }
447 
448 /******************************************************************************/
449 
450 int XrdNet::do_Accept_TCP(XrdNetPeer &myPeer, int opts)
451 {
452  XrdNetAddr tAddr;
453  char hBuff[512];
454 
455 // Use the new interface to actually do the accept
456 //
457  if (!do_Accept_TCP(tAddr, opts)) return 0;
458 
459 // Now transfor it back to the old-style interface
460 //
461  memcpy(&myPeer.Inet, tAddr.SockAddr(), tAddr.SockSize());
462  myPeer.fd = tAddr.SockFD();
463  tAddr.Format(hBuff, sizeof(hBuff), XrdNetAddr::fmtAuto, false);
464  if (myPeer.InetName) free(myPeer.InetName);
465  myPeer.InetName = strdup(hBuff);
466  return 1;
467 }
468 
469 /******************************************************************************/
470 /* d o _ A c c e p t _ U D P */
471 /******************************************************************************/
472 
473 int XrdNet::do_Accept_UDP(XrdNetPeer &myPeer, int opts)
474 {
475  char hBuff[512];
476  int dlen;
477  XrdNetSockAddr IP;
478  SOCKLEN_t addrlen = sizeof(IP);
479  XrdNetBuffer *bp;
480  XrdNetAddr uAddr;
481 
482 // For UDP connections, get a buffer for the message. To be thread-safe, we
483 // must actually receive the message to maintain the host-datagram pairing.
484 //
485  if (!(bp = BuffQ->Alloc()))
486  {eDest->Emsg("Accept", ENOMEM, "accept UDP message");
487  return 0;
488  }
489 
490 // Read the message and get the host address
491 //
492  do {dlen = recvfrom(iofd,(Sokdata_t)bp->data,BuffSize-1,0,&IP.Addr,&addrlen);
493  } while(dlen < 0 && errno == EINTR);
494 
495  if (dlen < 0)
496  {eDest->Emsg("Receive", errno, "perform UDP recvfrom()");
497  BuffQ->Recycle(bp);
498  return 0;
499  } else bp->data[dlen] = '\0';
500 
501 // Use the new-style address handling for address functions
502 //
503  uAddr.Set(&IP.Addr);
504 
505 // Authorize this connection. We don't accept messages that set the
506 // loopback address since this can be trivially spoofed in UDP packets.
507 //
508  if (uAddr.isLoopback() || (Police && !Police->Authorize(uAddr)))
509  {eDest->Emsg("Accept", -EACCES, "accept connection from",
510  uAddr.Name("*unknown*"));
511  BuffQ->Recycle(bp);
512  return 0;
513  } else uAddr.Format(hBuff, sizeof(hBuff),
517 // Get a new FD if so requested. We use our base FD for outgoing messages.
518 //
519  if (opts & XRDNET_NEWFD)
520  {myPeer.fd = XrdSysFD_Dup(iofd);
521  if (opts & XRDNET_NOCLOSEX) XrdSysFD_Yield(myPeer.fd);
522  } else myPeer.fd = iofd;
523 
524 // Fill in the peer structure.
525 //
526  memcpy(&myPeer.Inet, &IP, sizeof(myPeer.Inet));
527  if (myPeer.InetName) free(myPeer.InetName);
528  myPeer.InetName = strdup(hBuff);
529  if (myPeer.InetBuff) myPeer.InetBuff->Recycle();
530  myPeer.InetBuff = bp;
531  return 1;
532 }
#define XRDNET_NORLKUP
Definition: XrdNetOpts.hh:87
#define XRDNET_TOUT
Definition: XrdNetOpts.hh:110
#define XRDNET_NOCLOSEX
Definition: XrdNetOpts.hh:67
#define XRDNET_SERVER
Definition: XrdNetOpts.hh:99
#define XRDNET_NODNTRIM
Definition: XrdNetOpts.hh:51
#define XRDNET_NEWFD
Definition: XrdNetOpts.hh:39
#define XRDNET_SENDONLY
Definition: XrdNetOpts.hh:43
#define XRDNET_NOEMSG
Definition: XrdNetOpts.hh:71
#define XRDNET_UDPSOCKET
Definition: XrdNetOpts.hh:79
#define XRDNET_DELAY
Definition: XrdNetOpts.hh:59
#define XRDNET_UDPBUFFSZ
Definition: XrdNetOpts.hh:114
struct sockaddr Addr
#define close(a)
Definition: XrdPosix.hh:43
#define eMsg(x)
struct myOpts opts
#define SOCKLEN_t
#define Sokdata_t
static const int noPort
Do not add port number.
const sockaddr * SockAddr()
bool isIPType(IPType ipType) const
int Format(char *bAddr, int bLen, fmtUse fmtType=fmtAuto, int fmtOpts=0)
@ fmtName
Hostname if it is resolvable o/w use fmtAddr.
@ fmtAuto
Hostname if already resolved o/w use fmtAddr.
SOCKLEN_t SockSize()
const char * Name(const char *eName=0, const char **eText=0)
const char * Set(const char *hSpec, int pNum=PortInSpec)
Definition: XrdNetAddr.cc:216
XrdNetBuffer * Alloc()
Definition: XrdNetBuffer.cc:71
void Recycle(XrdNetBuffer *bp)
Definition: XrdNetBuffer.cc:99
void Recycle(void)
Definition: XrdNetBuffer.hh:81
XrdNetSockAddr Inet
Definition: XrdNetPeer.hh:43
XrdNetBuffer * InetBuff
Definition: XrdNetPeer.hh:45
char * InetName
Definition: XrdNetPeer.hh:44
bool Authorize(const char *hSpec)
void Merge(XrdNetSecurity *srcp)
int Open(const char *path, int port=-1, int flags=0, int sockbuffsz=0)
static int setOpts(int fd, int options, XrdSysError *eDest=0)
const char * Peername(const struct sockaddr **InetAddr=0, int *InetSize=0)
static int getWindow(int fd, int &Windowsz, XrdSysError *eDest=0)
static int Port(int fd, const char **eText=0)
Definition: XrdNetUtils.cc:780
char * Domain
Definition: XrdNet.hh:285
int Windowsz
Definition: XrdNet.hh:290
int Bind(int port, const char *contype="tcp")
Definition: XrdNet.cc:164
XrdNet(XrdSysError *erp, XrdNetSecurity *secp=0)
Definition: XrdNet.cc:60
int iofd
Definition: XrdNet.hh:287
XrdSysError * eDest
Definition: XrdNet.hh:283
XrdNetBufferQ * BuffQ
Definition: XrdNet.hh:293
XrdNetSecurity * Police
Definition: XrdNet.hh:284
int netOpts
Definition: XrdNet.hh:291
void unBind()
Unbind the network from any bound resouces.
Definition: XrdNet.cc:358
int Connect(XrdNetAddr &myAddr, const char *dest, int port=-1, int opts=0, int timeout=-1)
Definition: XrdNet.cc:252
int Relay(XrdNetPeer &Peer, const char *dest, int opts=0)
Definition: XrdNet.cc:310
int Domlen
Definition: XrdNet.hh:286
int Portnum
Definition: XrdNet.hh:288
int BuffSize
Definition: XrdNet.hh:292
int Accept(XrdNetAddr &myAddr, int opts=0, int timeout=-1)
Definition: XrdNet.cc:84
virtual void Secure(XrdNetSecurity *secp)
Definition: XrdNet.cc:329
int WSize()
Definition: XrdNet.cc:368
virtual ~XrdNet()
Destructor.
Definition: XrdNet.cc:74
int PortType
Definition: XrdNet.hh:289
void Trim(char *hname)
Definition: XrdNet.cc:343
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:95