XRootD
Loading...
Searching...
No Matches
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"
46#include "XrdNet/XrdNetOpts.hh"
47#include "XrdNet/XrdNetPeer.hh"
50#include "XrdNet/XrdNetUtils.hh"
51
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;
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
84int 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
125int 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
164int 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
206int 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
252int 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
310int XrdNet::Relay(XrdNetPeer &Peer, const char *dest, int opts)
311{
312 return Connect(Peer, dest, -1, opts | XRDNET_UDPSOCKET);
313}
314
315/******************************************************************************/
316
317int 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
343void 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
383int XrdNet::do_Accept_TCP(XrdNetAddr &hAddr, int opts)
384{
385 static int noAcpt = 0;
387 SOCKLEN_t addrlen = sizeof(IP);
388 int newfd;
389
390// Remove UDP option if present
391//
392 opts &= ~XRDNET_UDPSOCKET;
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),
431 : XrdNetAddr::fmtName),
432 XrdNetAddrInfo::noPort);
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
450int 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
473int XrdNet::do_Accept_UDP(XrdNetPeer &myPeer, int opts)
474{
475 char hBuff[512];
476 int dlen;
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),
515 : XrdNetAddr::fmtName),
516 XrdNetAddrInfo::noPort);
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_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
struct sockaddr Addr
#define close(a)
Definition XrdPosix.hh:48
#define eMsg(x)
struct myOpts opts
#define SOCKLEN_t
#define Sokdata_t
const sockaddr * SockAddr()
bool isIPType(IPType ipType) const
int Format(char *bAddr, int bLen, fmtUse fmtType=fmtAuto, int fmtOpts=0)
@ 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)
XrdNetBuffer * Alloc()
void Recycle(XrdNetBuffer *bp)
void Recycle(void)
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)
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)