00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 const char *XrdNetSocketCVSID = "$Id: XrdNetSocket.cc 35287 2010-09-14 21:19:35Z ganis $";
00014
00015 #ifndef WIN32
00016 #include <unistd.h>
00017 #include <errno.h>
00018 #include <fcntl.h>
00019 #include <poll.h>
00020 #include <stdio.h>
00021 #include <stdlib.h>
00022 #include <strings.h>
00023 #include <netinet/in.h>
00024 #include <netinet/tcp.h>
00025 #include <sys/types.h>
00026 #include <sys/socket.h>
00027 #include <sys/stat.h>
00028 #include <sys/un.h>
00029 #else
00030 #include <errno.h>
00031 #include <fcntl.h>
00032 #include <stdio.h>
00033 #include <stdlib.h>
00034 #include <sys/types.h>
00035 #include <sys/stat.h>
00036 #include <Winsock2.h>
00037 #include "XrdSys/XrdWin32.hh"
00038 #endif
00039
00040 #include "XrdNet/XrdNetConnect.hh"
00041 #include "XrdNet/XrdNetDNS.hh"
00042 #include "XrdNet/XrdNetOpts.hh"
00043 #include "XrdNet/XrdNetSocket.hh"
00044 #include "XrdSys/XrdSysError.hh"
00045 #include "XrdOuc/XrdOucUtils.hh"
00046 #include "XrdSys/XrdSysPlatform.hh"
00047
00048
00049
00050
00051
00052 #define XRDNETSOCKET_MAXBKLG 255
00053 #define XRDNETSOCKET_LINGER 3
00054
00055 #define Err(p,a,b,c) (ErrCode = (eroute ? eroute->Emsg(#p, a, b, c) : ErrCode),-1)
00056
00057
00058
00059
00060
00061 XrdNetSocket::XrdNetSocket(XrdSysError *erobj, int SockFileDesc)
00062 {
00063 ErrCode = 0;
00064 PeerName = 0;
00065 SockFD = SockFileDesc;
00066 eroute = erobj;
00067 }
00068
00069
00070
00071
00072
00073 int XrdNetSocket::Accept(int timeout)
00074 {
00075 int retc, ClientSock;
00076
00077 ErrCode = 0;
00078
00079
00080
00081 if (timeout >= 0)
00082 {struct pollfd sfd = {SockFD,
00083 POLLIN|POLLRDNORM|POLLRDBAND|POLLPRI|POLLHUP, 0};
00084 do {retc = poll(&sfd, 1, timeout);}
00085 while(retc < 0 && (errno == EAGAIN || errno == EINTR));
00086 if (!sfd.revents) return -1;
00087 }
00088
00089 do {ClientSock = accept(SockFD, (struct sockaddr *)0, 0);}
00090 while(ClientSock < 0 && errno == EINTR);
00091
00092 if (ClientSock < 0 && eroute) eroute->Emsg("Accept",errno,"accept connection");
00093
00094
00095
00096 return ClientSock;
00097 }
00098
00099
00100
00101
00102
00103 void XrdNetSocket::Close()
00104 {
00105
00106
00107 if (SockFD >= 0) {close(SockFD); SockFD=-1;}
00108
00109
00110
00111 if (PeerName) {free(PeerName); PeerName = 0;}
00112
00113
00114
00115 ErrCode=0;
00116 }
00117
00118
00119
00120
00121
00122 XrdNetSocket *XrdNetSocket::Create(XrdSysError *Say, const char *path,
00123 const char *fn, mode_t mode, int opts)
00124 {
00125 XrdNetSocket *ASock;
00126 int pflags = (opts & XRDNET_FIFO ? S_IFIFO : S_IFSOCK);
00127 int sflags = (opts & XRDNET_UDPSOCKET) | XRDNET_SERVER;
00128 int rc = 0;
00129 mode_t myMode = (mode & (S_IRWXU | S_IRWXG));
00130 const char *eMsg = 0;
00131 char fnbuff[1024] = {0};
00132
00133
00134
00135 if (!socketPath(Say, fnbuff, path, fn, mode|pflags))
00136 return (XrdNetSocket *)0;
00137
00138
00139
00140 ASock = new XrdNetSocket(Say);
00141 #ifndef WIN32
00142 if (opts & XRDNET_FIFO)
00143 {if ((ASock->SockFD = mkfifo(fnbuff, mode)) < 0 && errno != EEXIST)
00144 {eMsg = "create fifo"; rc = errno;}
00145 else if ((ASock->SockFD = open(fnbuff, O_RDWR, myMode)) < 0)
00146 {eMsg = "open fifo"; rc = ASock->LastError();}
00147 } else if (ASock->Open(fnbuff, -1, sflags) < 0)
00148 {eMsg = "create socket"; rc = ASock->LastError();}
00149 #else
00150 if (ASock->Open(fnbuff, -1, sflags) < 0)
00151 {eMsg = "create socket"; rc = ASock->LastError();}
00152 #endif
00153
00154
00155
00156 if (eMsg) {Say->Emsg("Create", rc, eMsg, fnbuff);
00157 delete ASock; ASock = 0;
00158 }
00159 return ASock;
00160 }
00161
00162
00163
00164
00165
00166 int XrdNetSocket::Detach()
00167 { int oldFD = SockFD;
00168 SockFD = -1;
00169 if (PeerName) {free(PeerName); PeerName = 0;}
00170 return oldFD;
00171 }
00172
00173
00174
00175
00176
00177 int XrdNetSocket::getWindow(int fd, int &Windowsz, XrdSysError *eDest)
00178 {
00179 socklen_t szb = (socklen_t)sizeof(Windowsz);
00180
00181 if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, (Sokdata_t)&Windowsz, &szb))
00182 {if (eDest) eDest->Emsg("setWindow", errno, "set socket RCVBUF");
00183 return -1;
00184 }
00185 return 0;
00186 }
00187
00188
00189
00190
00191
00192 int XrdNetSocket::Open(const char *inpath, int port, int flags, int windowsz)
00193 {
00194 struct sockaddr_in InetAddr;
00195 struct sockaddr_un UnixAddr;
00196 struct sockaddr *SockAddr;
00197 char *errtxt = 0, pbuff[128];
00198 const char *action = "configure socket";
00199 const char *path = (inpath ? inpath : "");
00200 const char *epath= (inpath ? inpath : pbuff);
00201 int myEC, SockSize, backlog;
00202 int SockType = (flags & XRDNET_UDPSOCKET ? SOCK_DGRAM : SOCK_STREAM);
00203 const int one = 1;
00204 const SOCKLEN_t szone = (SOCKLEN_t)sizeof(one);
00205
00206
00207
00208 if (!inpath) sprintf(pbuff, "port %d", port);
00209
00210
00211
00212 if (SockFD >= 0) return Err(Open, EBUSY, "create socket for", epath);
00213
00214
00215
00216 myEC = ErrCode = 0;
00217
00218
00219
00220
00221
00222
00223
00224
00225 if (port < 0 && *path == '/')
00226 {if (strlen(path) >= sizeof(UnixAddr.sun_path))
00227 return Err(Open, ENAMETOOLONG, "create unix socket ", epath);
00228 if ((SockFD = socket(PF_UNIX, SockType, 0)) < 0)
00229 return Err(Open, errno, "create unix socket ", epath);
00230 UnixAddr.sun_family = AF_UNIX;
00231 strcpy(UnixAddr.sun_path, path);
00232 SockAddr = (struct sockaddr *)&UnixAddr;
00233 SockSize = sizeof(UnixAddr);
00234 if (flags & XRDNET_SERVER) unlink((const char *)path);
00235 } else {
00236 if ((SockFD = socket(PF_INET, SockType, 0)) < 0)
00237 return Err(Open, errno, "create inet socket to", epath);
00238 if (port < 0 && *path)
00239 XrdNetDNS::Host2Dest(inpath,(sockaddr &)InetAddr,&errtxt);
00240 else {XrdNetDNS::getHostAddr(path,(sockaddr &)InetAddr,&errtxt);
00241 XrdNetDNS::setPort((sockaddr &)InetAddr, port);
00242 }
00243 if (errtxt)
00244 {if(eroute) eroute->Emsg("Open", "Unable to obtain address for",
00245 epath, errtxt);
00246 Close();
00247 ErrCode = EHOSTUNREACH;
00248 return -1;
00249 }
00250 SockAddr = (struct sockaddr *)&InetAddr;
00251 SockSize = sizeof(InetAddr);
00252 }
00253
00254
00255
00256 setOpts(SockFD, (flags | (*path == '/' ? XRDNET_UDPSOCKET : 0)), eroute);
00257 if (windowsz) setWindow(SockFD, windowsz, eroute);
00258
00259
00260
00261 if ((*path != '/') && setsockopt(SockFD,SOL_SOCKET,SO_REUSEADDR,
00262 (Sokdata_t)&one, szone) && eroute)
00263 eroute->Emsg("open", errno, "set socket REUSEADDR");
00264
00265
00266
00267 if (flags & XRDNET_SERVER)
00268 {action = "bind socket to";
00269 if ( bind(SockFD, SockAddr, SockSize) ) myEC = errno;
00270 else if (SockType == SOCK_STREAM)
00271 {action = "listen on stream";
00272 if (!(backlog = flags & XRDNET_BKLG))
00273 backlog = XRDNETSOCKET_MAXBKLG;
00274 if (listen(SockFD, backlog)) myEC = errno;
00275 }
00276 if (*path == '/') chmod(path, S_IRWXU);
00277 } else {
00278 if (SockType == SOCK_STREAM)
00279 {int tmo = flags & XRDNET_TOUT;
00280 action = "connect socket to";
00281 if (tmo) myEC = XrdNetConnect::Connect(SockFD,SockAddr,SockSize,tmo);
00282 else if (connect(SockFD, SockAddr, SockSize)) myEC = errno;
00283 }
00284 if (!myEC) {PeerName = strdup((path ? path : "?"));
00285 if (*path == '/') XrdNetDNS::getHostAddr(0, PeerAddr);
00286 else memcpy((void *)&PeerAddr,SockAddr,sizeof(PeerAddr));
00287 }
00288 }
00289
00290
00291
00292 if (myEC)
00293 {Close();
00294 ErrCode = myEC;
00295 if (!(flags & XRDNET_NOEMSG) && eroute)
00296 eroute->Emsg("Open", ErrCode, action, epath);
00297 return -1;
00298 }
00299 return SockFD;
00300 }
00301
00302
00303
00304
00305
00306 const char *XrdNetSocket::Peername(struct sockaddr **InetAddr)
00307 {
00308 char *errtxt;
00309
00310
00311
00312 if (SockFD < 0)
00313 {if (eroute) eroute->Emsg("Peername",
00314 "Unable to obtain peer name; socket not open");
00315 return (char *)0;
00316 }
00317
00318
00319
00320 if (!PeerName
00321 && !(PeerName = XrdNetDNS::Peername(SockFD, &PeerAddr, &errtxt)))
00322 {if (eroute)
00323 eroute->Emsg("Peername", "Unable to obtain peer name;",errtxt);
00324 ErrCode = ESRCH;
00325 }
00326
00327
00328
00329 if (InetAddr) *InetAddr = &PeerAddr;
00330 return PeerName;
00331 }
00332
00333
00334
00335
00336
00337 int XrdNetSocket::setOpts(int xfd, int opts, XrdSysError *eDest)
00338 {
00339 int rc = 0;
00340 const int one = 1;
00341 const SOCKLEN_t szone = (SOCKLEN_t)sizeof(one);
00342 static int tcpprotid = XrdNetDNS::getProtoID("tcp");
00343 static struct linger liopts = {1, XRDNETSOCKET_LINGER};
00344 const SOCKLEN_t szlio = (SOCKLEN_t)sizeof(liopts);
00345
00346 if (!(opts & XRDNET_NOCLOSEX) && fcntl(xfd, F_SETFD, FD_CLOEXEC))
00347 {rc = 1;
00348 if (eDest) eDest->Emsg("setOpts", errno, "set fd close on exec");
00349 }
00350
00351 if (opts & XRDNET_UDPSOCKET) return rc;
00352
00353 if (!(opts & XRDNET_NOLINGER)
00354 && setsockopt(xfd,SOL_SOCKET,SO_LINGER,(Sokdata_t)&liopts,szlio))
00355 {rc = 1;
00356 if (eDest) eDest->Emsg("setOpts", errno, "set socket LINGER");
00357 }
00358
00359 if ((opts & XRDNET_KEEPALIVE)
00360 && setsockopt(xfd,SOL_SOCKET,SO_KEEPALIVE,(Sokdata_t)&one,szone))
00361 {rc = 1;
00362 if (eDest) eDest->Emsg("setOpts", errno, "set socket KEEPALIVE");
00363 }
00364
00365 if (!(opts & XRDNET_DELAY)
00366 && setsockopt(xfd, tcpprotid, TCP_NODELAY, (Sokdata_t)&one,szone))
00367 {rc = 1;
00368 if (eDest) eDest->Emsg("setOpts", errno, "set socket NODELAY");
00369 }
00370
00371 return rc;
00372 }
00373
00374
00375
00376
00377
00378 int XrdNetSocket::setWindow(int xfd, int Windowsz, XrdSysError *eDest)
00379 {
00380 int rc = 0;
00381 const SOCKLEN_t szwb = (SOCKLEN_t)sizeof(Windowsz);
00382
00383 if (setsockopt(xfd, SOL_SOCKET, SO_SNDBUF,
00384 (Sokdata_t)&Windowsz, szwb))
00385 {rc = 1;
00386 if (eDest) eDest->Emsg("setWindow", errno, "set socket SNDBUF");
00387 }
00388
00389 if (setsockopt(xfd, SOL_SOCKET, SO_RCVBUF,
00390 (Sokdata_t)&Windowsz, szwb))
00391 {rc = 1;
00392 if (eDest) eDest->Emsg("setWindow", errno, "set socket RCVBUF");
00393 }
00394 return rc;
00395 }
00396
00397
00398
00399
00400
00401 const char *XrdNetSocket::socketAddr(XrdSysError *Say, const char *dest,
00402 struct sockaddr **sockAP, int &sockAL)
00403 {
00404 struct sockaddr_in InetAddr;
00405 struct sockaddr_un UnixAddr;
00406 struct sockaddr *SockAddr;
00407 char *errtxt = 0;
00408 int port = 0, SockSize;
00409
00410 if (*dest == '/')
00411 {if (strlen(dest) >= sizeof(UnixAddr.sun_path))
00412 {if (Say) Say->Emsg("Net", ENAMETOOLONG, "generate addr from", dest);
00413 return "socket address path too long";
00414 }
00415 UnixAddr.sun_family = AF_UNIX;
00416 strcpy(UnixAddr.sun_path, dest);
00417 SockAddr = (struct sockaddr *)&UnixAddr;
00418 SockSize = sizeof(UnixAddr);
00419 } else {
00420 if (*dest && *dest != ':')
00421 XrdNetDNS::Host2Dest(dest,(sockaddr &)InetAddr,&errtxt);
00422 else {XrdNetDNS::getHostAddr(dest,(sockaddr &)InetAddr,&errtxt);
00423 if (*dest && *dest == ':') port = atoi(dest+1);
00424 XrdNetDNS::setPort((sockaddr &)InetAddr, port);
00425 }
00426 if (errtxt)
00427 {if (Say) Say->Emsg("Net","Unable to obtain address for",dest,errtxt);
00428 return errtxt;
00429 }
00430 SockAddr = (struct sockaddr *)&InetAddr;
00431 SockSize = sizeof(InetAddr);
00432 }
00433
00434 sockAL = SockSize;
00435 *sockAP = (struct sockaddr *)malloc(SockSize);
00436 memcpy(*sockAP, SockAddr, SockSize);
00437 return 0;
00438 }
00439
00440
00441
00442
00443
00444 char *XrdNetSocket::socketPath(XrdSysError *Say, char *fnbuff,
00445 const char *path, const char *fn, mode_t mode)
00446 {
00447 const int srchOK = S_IXUSR | S_IXGRP;
00448 const int sfMask = (S_IFIFO | S_IFSOCK);
00449 int rc, i, fnlen = strlen(fnbuff);
00450 mode_t myMode = (mode & (S_IRWXU | S_IRWXG)) | srchOK;
00451 struct stat buf;
00452 char *sp = 0;
00453
00454
00455
00456 i = strlen(path);
00457 if (strlcpy(fnbuff, path, 1024) >= 1024 || (i + fnlen + 1) >= 1024)
00458 {Say->Emsg("createPath", "Socket path", path, "too long");
00459 return 0;
00460 }
00461
00462
00463
00464 if (!fn)
00465 {if (fnbuff[i-1] == '/') fnbuff[i-1] = '\0';
00466 if ((sp = rindex(fnbuff, '/'))) *sp = '\0';
00467 }
00468
00469
00470
00471 if ((rc = XrdOucUtils::makePath(fnbuff, myMode)))
00472 {Say->Emsg("createPath", errno, "create path", path);
00473 return 0;
00474 }
00475
00476
00477
00478 if (sp) *sp = '/';
00479 else {if (path[i-1] != '/') fnbuff[i++] = '/';
00480 if (fn) strcpy(fnbuff+i, fn);
00481 }
00482
00483
00484
00485 if (!stat(fnbuff,&buf))
00486 {if ((buf.st_mode & S_IFMT) != (mode & sfMask))
00487 {Say->Emsg("createPath","Path",fnbuff,
00488 (mode & S_IFSOCK) ? "exists but is not a socket"
00489 : "exists but is not a pipe");
00490 return 0;
00491 }
00492 if (access(fnbuff, W_OK))
00493 {Say->Emsg("cratePath", errno, "access path", fnbuff);
00494 return 0;
00495 }
00496 } else chmod(fnbuff, mode);
00497
00498
00499
00500 return fnbuff;
00501 }