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 {const char* sn;
291 memset((void *)&myPeer.Inet, 0, sizeof(myPeer.Inet));
292 if (host && (sn = mySocket.SockData(myPeer.Inet)))
293 {myPeer.InetName = strdup(sn);}
294 else myPeer.InetName = 0;
295 } else {
296 const char *pn = mySocket.Peername(&sap);
297 if (pn) {memcpy((void *)&myPeer.Inet, sap, sizeof(myPeer.Inet));
298 myPeer.InetName = strdup(pn);
299 if (Domain && !(opts & XRDNET_NODNTRIM)) Trim(myPeer.InetName);
300 } else {
301 memset((void *)&myPeer.Inet, 0, sizeof(myPeer.Inet));
302 myPeer.InetName = strdup("unknown!");
303 }
304 }
305 myPeer.fd = mySocket.Detach();
306 return 1;
307}
308
309/******************************************************************************/
310/* R e l a y */
311/******************************************************************************/
312
313int XrdNet::Relay(XrdNetPeer &Peer, const char *dest, int opts)
314{
315 return Connect(Peer, dest, -1, opts | XRDNET_UDPSOCKET);
316}
317
318/******************************************************************************/
319
320int XrdNet::Relay(const char *dest)
321{
322 XrdNetPeer myPeer;
323
324 return (Connect(myPeer, dest, -1, XRDNET_UDPSOCKET | XRDNET_SENDONLY)
325 ? myPeer.fd : -1);
326}
327
328/******************************************************************************/
329/* S e c u r e */
330/******************************************************************************/
331
333{
334
335// If we don't have a Police object then use the one supplied. Otherwise
336// merge the supplied object into the existing object.
337//
338 if (Police) Police->Merge(secp);
339 else Police = secp;
340}
341
342/******************************************************************************/
343/* T r i m */
344/******************************************************************************/
345
346void XrdNet::Trim(char *hname)
347{
348 int k = strlen(hname);
349 char *hnp;
350
351 if (Domlen && k > Domlen)
352 {hnp = hname + (k - Domlen);
353 if (!strcmp(Domain, hnp)) *hnp = '\0';
354 }
355}
356
357/******************************************************************************/
358/* u n B i n d */
359/******************************************************************************/
360
362{
363 if (iofd >= 0) {close(iofd); iofd=-1; Portnum=0;}
364 if (BuffQ) {delete BuffQ; BuffQ = 0;}
365}
366
367/******************************************************************************/
368/* W S i z e */
369/******************************************************************************/
370
372{
373 int wsz;
374
375 if (iofd >= 0 && !XrdNetSocket::getWindow(iofd, wsz, eDest)) return wsz;
376 return 0;
377}
378
379/******************************************************************************/
380/* P r i v a t e M e t h o d s */
381/******************************************************************************/
382/******************************************************************************/
383/* d o _ A c c e p t _ T C P */
384/******************************************************************************/
385
386int XrdNet::do_Accept_TCP(XrdNetAddr &hAddr, int opts)
387{
388 static int noAcpt = 0;
390 SOCKLEN_t addrlen = sizeof(IP);
391 int newfd;
392
393// Remove UDP option if present
394//
396
397// Accept a connection
398//
399 do {newfd = XrdSysFD_Accept(iofd, &IP.Addr, &addrlen);}
400 while(newfd < 0 && errno == EINTR);
401
402 if (newfd < 0)
403 {if (!(opts & XRDNET_NOEMSG) && (errno != EMFILE || !(0x1ff & noAcpt++)))
404 eDest->Emsg("Accept", errno, "perform accept");
405 return 0;
406 }
407
408// Initialize the address of the new connection
409//
410 const char *eMsg = hAddr.Set(&IP.Addr, newfd);
411 if (eMsg)
412 {char buff[256];
413 snprintf(buff, sizeof(buff), "%d;", newfd);
414 eDest->Emsg("Accept", "Failed to identify FD", buff, eMsg);
415 close(newfd);
416 return 0;
417 }
418
419// Remove TCP_NODELAY option for unix domain sockets to avoid error message
420//
422
423// Set all required fd options are set
424//
426
427// Authorize by ip address or full (slow) hostname format
428//
429 if (Police)
430 {if (!Police->Authorize(hAddr))
431 {char ipbuff[512];
432 hAddr.Format(ipbuff, sizeof(ipbuff),
436 eDest->Emsg("Accept",EACCES,"accept TCP connection from",ipbuff);
437 close(newfd);
438 return 0;
439 }
440 }
441
442// Force resolution of the addres unless reverse lookup not desired
443//
444 if (!(opts & XRDNET_NORLKUP)) hAddr.Name();
445
446// All done
447//
448 return 1;
449}
450
451/******************************************************************************/
452
453int XrdNet::do_Accept_TCP(XrdNetPeer &myPeer, int opts)
454{
455 XrdNetAddr tAddr;
456 char hBuff[512];
457
458// Use the new interface to actually do the accept
459//
460 if (!do_Accept_TCP(tAddr, opts)) return 0;
461
462// Now transfor it back to the old-style interface
463//
464 memcpy(&myPeer.Inet, tAddr.SockAddr(), tAddr.SockSize());
465 myPeer.fd = tAddr.SockFD();
466 tAddr.Format(hBuff, sizeof(hBuff), XrdNetAddr::fmtAuto, false);
467 if (myPeer.InetName) free(myPeer.InetName);
468 myPeer.InetName = strdup(hBuff);
469 return 1;
470}
471
472/******************************************************************************/
473/* d o _ A c c e p t _ U D P */
474/******************************************************************************/
475
476int XrdNet::do_Accept_UDP(XrdNetPeer &myPeer, int opts)
477{
478 char hBuff[512];
479 int dlen;
480 XrdNetSockAddr IP;
481 SOCKLEN_t addrlen = sizeof(IP);
482 XrdNetBuffer *bp;
483 XrdNetAddr uAddr;
484
485// For UDP connections, get a buffer for the message. To be thread-safe, we
486// must actually receive the message to maintain the host-datagram pairing.
487//
488 if (!(bp = BuffQ->Alloc()))
489 {eDest->Emsg("Accept", ENOMEM, "accept UDP message");
490 return 0;
491 }
492
493// Read the message and get the host address
494//
495 do {dlen = recvfrom(iofd,(Sokdata_t)bp->data,BuffSize-1,0,&IP.Addr,&addrlen);
496 } while(dlen < 0 && errno == EINTR);
497
498 if (dlen < 0)
499 {eDest->Emsg("Receive", errno, "perform UDP recvfrom()");
500 BuffQ->Recycle(bp);
501 return 0;
502 } else bp->data[dlen] = '\0';
503
504// Use the new-style address handling for address functions
505//
506 uAddr.Set(&IP.Addr);
507
508// Authorize this connection. We don't accept messages that set the
509// loopback address since this can be trivially spoofed in UDP packets.
510//
511 if (uAddr.isLoopback() || (Police && !Police->Authorize(uAddr)))
512 {eDest->Emsg("Accept", -EACCES, "accept connection from",
513 uAddr.Name("*unknown*"));
514 BuffQ->Recycle(bp);
515 return 0;
516 } else uAddr.Format(hBuff, sizeof(hBuff),
520// Get a new FD if so requested. We use our base FD for outgoing messages.
521//
522 if (opts & XRDNET_NEWFD)
523 {myPeer.fd = XrdSysFD_Dup(iofd);
524 if (opts & XRDNET_NOCLOSEX) XrdSysFD_Yield(myPeer.fd);
525 } else myPeer.fd = iofd;
526
527// Fill in the peer structure.
528//
529 memcpy(&myPeer.Inet, &IP, sizeof(myPeer.Inet));
530 if (myPeer.InetName) free(myPeer.InetName);
531 myPeer.InetName = strdup(hBuff);
532 if (myPeer.InetBuff) myPeer.InetBuff->Recycle();
533 myPeer.InetBuff = bp;
534 return 1;
535}
#define XRDNET_NORLKUP
Definition XrdNetOpts.hh:87
#define XRDNET_TOUT
#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
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)
void Recycle(void)
XrdNetSockAddr Inet
Definition XrdNetPeer.hh:43
XrdNetBuffer * InetBuff
Definition XrdNetPeer.hh:45
char * InetName
Definition XrdNetPeer.hh:44
const char * SockData(XrdNetSockAddr &InetAddr)
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:288
int Windowsz
Definition XrdNet.hh:293
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:290
XrdSysError * eDest
Definition XrdNet.hh:286
XrdNetBufferQ * BuffQ
Definition XrdNet.hh:296
XrdNetSecurity * Police
Definition XrdNet.hh:287
int netOpts
Definition XrdNet.hh:294
void unBind()
Unbind the network from any bound resouces.
Definition XrdNet.cc:361
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:313
int Domlen
Definition XrdNet.hh:289
int Portnum
Definition XrdNet.hh:291
int BuffSize
Definition XrdNet.hh:295
int Accept(XrdNetAddr &myAddr, int opts=0, int timeout=-1)
Definition XrdNet.cc:84
virtual void Secure(XrdNetSecurity *secp)
Definition XrdNet.cc:332
int WSize()
Definition XrdNet.cc:371
virtual ~XrdNet()
Destructor.
Definition XrdNet.cc:74
int PortType
Definition XrdNet.hh:292
void Trim(char *hname)
Definition XrdNet.cc:346