xref: /titanic_41/usr/src/cmd/lms/tools/ATNetworkTool.cpp (revision f34a71784df3fbc5d1227a7b6201fd318ad1667e)
1 /*******************************************************************************
2  * Copyright (C) 2004-2008 Intel Corp. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *  - Redistributions of source code must retain the above copyright notice,
8  *    this list of conditions and the following disclaimer.
9  *
10  *  - Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  *
14  *  - Neither the name of Intel Corp. nor the names of its
15  *    contributors may be used to endorse or promote products derived from this
16  *    software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL Intel Corp. OR THE CONTRIBUTORS
22  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  *******************************************************************************/
30 
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34 
35 #include "ATNetworkTool.h"
36 #include <sstream>
37 #include <algorithm>
38 #include <cerrno>
39 #include <net/if.h>
40 #include <netdb.h>
41 
42 #ifdef __sun
43 #include <arpa/inet.h>
44 #include <sys/sockio.h>
45 #include <stdio.h>
46 #include <stropts.h>
47 #else
48 #include <ifaddrs.h>
49 #endif // __sun
50 
51 #include <unistd.h>
52 #include <fcntl.h>
53 
54 bool ATNetworkTool::GetHostNameDomain(const char *name, std::string &domain)
55 {
56 	const char *domp = strchr(name, '.');
57 	if (domp) {
58 		domp++;
59 		if (*domp) {
60 #ifdef LMS_NET_DEBUG
61 			printf("D:  %s\n", domp);
62 #endif
63 			domain = domp;
64 			return true;
65 		}
66 	}
67 	return false;
68 }
69 
70 bool ATNetworkTool::GetHentDomain(struct hostent *hent, std::string &domain)
71 {
72 	if (NULL == hent) {
73 		return false;
74 	}
75 	if (NULL == hent->h_name) {
76 		return false;
77 	}
78 
79 #ifdef LMS_NET_DEBUG
80 	printf("N:  %s\n", hent->h_name);
81 #endif
82 	if (ATNetworkTool::GetHostNameDomain(hent->h_name, domain)) {
83 		return true;
84 	}
85 
86 	if (NULL != hent->h_aliases) {
87 		for (char **ssx = hent->h_aliases; ssx && *ssx; ssx++) {
88 #ifdef LMS_NET_DEBUG
89 			printf("A:  %s\n", *ssx);
90 #endif
91 			if (ATNetworkTool::GetHostNameDomain(*ssx, domain)) {
92 				return true;
93 			}
94 		}
95 	}
96 	return false;
97 }
98 
99 bool ATNetworkTool::GetIPDomain(const ATAddress &ip, std::string &domain, int &error)
100 {
101 	char hbuf[NI_MAXHOST];
102 
103 	if (0 != (error = getnameinfo(ip.addr(), ip.size(),
104 				      hbuf, sizeof(hbuf),
105 				      NULL, 0,
106 				      NI_NAMEREQD))) {
107 		return false;
108 	}
109 
110 	return ATNetworkTool::GetHostNameDomain(hbuf, domain);
111 }
112 
113 int ATNetworkTool::GetLocalIPs(ATAddressList &addresses, int &error, int family, bool withloopback)
114 {
115 	struct ifaddrs *ifap;
116 
117 #ifdef __sun
118 
119 	char          buf[1024];
120 	struct ifconf ifc;
121 	struct ifreq *ifr;
122 	int           sock;
123 	int           nInterfaces;
124 	int           i;
125 
126 	addresses.clear();
127 
128 	sock = socket(AF_INET, SOCK_DGRAM, 0);
129 	if(sock < 0)
130 	{
131 		perror("socket");
132 		return 1;
133 	}
134 
135 	/* Query available interfaces. */
136 	ifc.ifc_len = sizeof(buf);
137 	ifc.ifc_buf = buf;
138 	if(ioctl(sock, SIOCGIFCONF, &ifc) < 0)
139 	{
140 		perror("ioctl(SIOCGIFCONF)");
141 		close(sock);
142 		return 1;
143 	}
144 
145 	/* Iterate through the list of interfaces. */
146 	ifr         = ifc.ifc_req;
147 	nInterfaces = ifc.ifc_len / sizeof(struct ifreq);
148 	for(i = 0; i < nInterfaces; i++)
149 	{
150 		struct ifreq *item = &ifr[i];
151 
152 		if (item->ifr_flags & IFF_LOOPBACK)
153 			continue;
154 
155 		addresses.insert(&item->ifr_addr);
156 	}
157 
158 	close(sock);
159 
160 #else // ! __sun
161 
162 	if (0 != getifaddrs(&ifap)) {
163 		error = errno;
164 		return -1;
165 	}
166 
167 	addresses.clear();
168 	for (struct ifaddrs *ifa = ifap; ifa; ifa = ifa->ifa_next) {
169 		if (NULL == ifa->ifa_addr) {
170 			continue;
171 		}
172 		if ((ifa->ifa_flags & IFF_UP) == 0) {
173 			continue;
174 		}
175 		if ((!withloopback) &&
176 		    (((ifa->ifa_flags & IFF_LOOPBACK) != 0) ||
177 		    ((ifa->ifa_flags & (IFF_BROADCAST | IFF_POINTOPOINT)) == 0))) {
178 			continue;
179 		}
180 
181 		if (AF_UNSPEC != family) {
182 			if (ATNetworkTool::AF_XINETX == family) {
183 				if (!ATAddress::saIsInet(ifa->ifa_addr)) {
184 					continue;
185 				}
186 			} else {
187 				if (ifa->ifa_addr->sa_family != family) {
188 					continue;
189 				}
190 			}
191 		}
192 
193 		addresses.insert(ifa->ifa_addr);
194 	}
195 	freeifaddrs(ifap);
196 
197 #endif // __sun
198 
199 	return 0;
200 }
201 
202 int ATNetworkTool::GetLocalNetDomains(ATDomainMap &domains, int &error, int family)
203 {
204 	int ret;
205 	ATAddressList addresses;
206 
207 	if (0 != (ret = ATNetworkTool::GetLocalIPs(addresses, error, family))) {
208 		return ret;
209 	}
210 
211 	domains.clear();
212 	ATAddressList::iterator aend = addresses.end();
213 	for (ATAddressList::iterator ait = addresses.begin();
214 	    ait != aend;
215 	    ait++)
216 	{
217 		std::string domain;
218 		if (ATNetworkTool::GetIPDomain(*ait, domain, error)) {
219 			domains[*ait] = domain;
220 		}
221 	}
222 	return 0;
223 }
224 
225 int ATNetworkTool::GetSockDomain(int sock, std::string &domain, int &error)
226 {
227 	struct sockaddr_storage ss;
228 	socklen_t salen = sizeof(ss);
229 	struct sockaddr *sa;
230 
231 	sa = (struct sockaddr *)&ss;
232 
233 	if (getsockname(sock, sa, &salen) != 0) {
234 		error = errno;
235 		return -1;
236 	}
237 
238 	if (ATNetworkTool::GetIPDomain(sa, domain, error)) {
239 		return 1;
240 	}
241 	return 0;
242 }
243 
244 int ATNetworkTool::GetSockPeerIPs(int sock, ATAddressList &addresses, int &error,
245 				  int family, bool zeroport)
246 {
247 	struct sockaddr_storage ss;
248 	socklen_t salen = sizeof(ss);
249 	struct sockaddr *sa;
250 	struct addrinfo hints, *paddr, *paddrp;
251 
252 	sa = (struct sockaddr *)&ss;
253 
254 	if (getpeername(sock, sa, &salen) != 0) {
255 		error = errno;
256 		return -1;
257 	}
258 
259 	char hbuf[NI_MAXHOST];
260 	char pbuf[NI_MAXSERV];
261 	if (0 != (error = getnameinfo(sa, salen,
262 				      hbuf, sizeof(hbuf),
263 				      pbuf, sizeof(pbuf),
264 				      0))) {
265 		return -1;
266 	}
267 
268 	memset(&hints, 0, sizeof(hints));
269 	if (ATNetworkTool::AF_XINETX == family) {
270 		hints.ai_family = PF_UNSPEC;
271 	} else {
272 		hints.ai_family = family;
273 	}
274 	hints.ai_socktype = SOCK_STREAM;
275 	if (0 != (error = getaddrinfo(hbuf, pbuf, &hints, &paddrp))) {
276 		return -1;
277 	}
278 	addresses.clear();
279 	for (paddr = paddrp; paddr; paddr = paddr->ai_next) {
280 		if (ATNetworkTool::AF_XINETX == family) {
281 			if (!ATAddress::saIsInet(paddr->ai_addr)) {
282 				continue;
283 			}
284 		}
285 		if (zeroport) {
286 			addresses.insert(ATAddress(paddr->ai_addr, 0));
287 		} else {
288 			addresses.insert(paddr->ai_addr);
289 		}
290 	}
291 	freeaddrinfo(paddrp);
292 	return 0;
293 }
294 
295 int ATNetworkTool::IsSockPeerLocal(int sock, int &error, int family)
296 {
297 	ATAddressList localAddresses;
298 	ATAddressList targAddresses;
299 
300 	if (0 != ATNetworkTool::GetSockPeerIPs(sock, targAddresses, error,
301 						family, true)) {
302 		return -1;
303 	}
304 	if (0 != ATNetworkTool::GetLocalIPs(localAddresses, error,
305 						family, true)) {
306 		return -1;
307 	}
308 	if (std::includes(localAddresses.begin(), localAddresses.end(),
309 			  targAddresses.begin(), targAddresses.end())) {
310 		return 1;
311 	}
312 	return 0;
313 }
314 
315 int ATNetworkTool::CloseSocket(int s)
316 {
317 	shutdown(s, SHUT_RDWR);
318 	return close(s);
319 }
320 
321 int ATNetworkTool::CreateSocket(const struct addrinfo *addr, int &error)
322 {
323 	return ATNetworkTool::CreateSocket(addr->ai_addr, addr->ai_addrlen,
324 					    error,
325 					    addr->ai_family, addr->ai_socktype,
326 					    addr->ai_protocol);
327 }
328 
329 int ATNetworkTool::CreateSocket(const struct sockaddr *addr, socklen_t addrlen,
330 				int &error,
331 				int family, int socktype, int protocol)
332 {
333 	int s = socket(family, socktype, protocol);
334 	if (s < 0) {
335 		error = errno;
336 		return -1;
337 	}
338 
339 	if (socktype != SOCK_DGRAM) {
340 		linger l;
341 		l.l_onoff = 0;
342 		l.l_linger = 0;
343 		if (setsockopt(s, SOL_SOCKET, SO_LINGER,
344 			       (char *)&l, sizeof(l)) == -1) {
345 			error = errno;
346 			close(s);
347 			return -1;
348 		}
349 	}
350 
351 	if (bind(s, addr, addrlen) == -1) {
352 		error = errno;
353 		close(s);
354 		return -1;
355 	}
356 
357 	return s;
358 }
359 
360 int ATNetworkTool::ConnectSocket(struct addrinfo *addr,
361 				 int &error, bool loopback)
362 {
363 	return ATNetworkTool::ConnectSocket(addr->ai_addr, addr->ai_addrlen,
364 					    error, loopback,
365 					    addr->ai_family, addr->ai_socktype,
366 					    addr->ai_protocol);
367 }
368 
369 int ATNetworkTool::ConnectSocket(const struct sockaddr *addr, socklen_t addrlen,
370 				 int &error, bool loopback,
371 				 int family, int socktype, int protocol)
372 {
373 	struct addrinfo hints, *paddr, *paddrp;
374 	int oks = -1;
375 
376 	memset(&hints, 0, sizeof(hints));
377 	if (ATNetworkTool::AF_XINETX == family) {
378 		hints.ai_family = PF_UNSPEC;
379 	} else {
380 		hints.ai_family = family;
381 	}
382 	hints.ai_socktype = socktype;
383 	hints.ai_protocol = protocol;
384 #ifdef AI_NUMERICSERV
385 	hints.ai_flags   |= AI_NUMERICSERV;
386 #endif
387 	if (!loopback) {
388 		hints.ai_flags |= AI_PASSIVE;
389 	}
390 	if ((error = getaddrinfo(NULL, "0", &hints, &paddrp)) != 0) {
391 		return -1;
392 	}
393 	for (paddr = paddrp; paddr; paddr = paddr->ai_next) {
394 		if (ATNetworkTool::AF_XINETX == family) {
395 			if (!ATAddress::saIsInet(paddr->ai_addr)) {
396 				continue;
397 			}
398 		}
399 
400 		int s = ATNetworkTool::CreateSocket(paddr, error);
401 		if (s < 0) {
402 			continue;
403 		}
404 
405 		if (connect(s, addr, addrlen) != 0) {
406 			error = errno;
407 			ATNetworkTool::CloseSocket(s);
408 			continue;
409 		}
410 
411 		oks = s;
412 		break;
413 	}
414 	freeaddrinfo(paddrp);
415 	return oks;
416 }
417 
418 int ATNetworkTool::CreateServerSocket(in_port_t port,
419 					int &error,
420 					bool loopback, bool nonblocking,
421 					int family, int socktype, int protocol,
422 					int backlog)
423 {
424 	std::stringstream ssport;
425 
426 	ssport << port;
427 	return ATNetworkTool::CreateServerSocket(ssport.str().c_str(),
428 						 error,
429 						 loopback, nonblocking,
430 						 family, socktype, protocol,
431 						 backlog);
432 }
433 
434 int ATNetworkTool::CreateServerSocket(const char *port,
435 					int &error,
436 					bool loopback, bool nonblocking,
437 					int family, int socktype, int protocol,
438 					int backlog)
439 {
440 	ATSocketList sockets;
441 	int s = -1;
442 
443 	int num = ATNetworkTool::CreateServerSockets(sockets, port,
444 						     error,
445 						     loopback, nonblocking,
446 						     family, socktype, protocol,
447 						     backlog, true);
448 	if ((num > 0) && (sockets.size() > 0)) {
449 		s = sockets[0];
450 	}
451 	sockets.clear();
452 	return s;
453 }
454 
455 
456 int ATNetworkTool::CreateServerSockets(ATSocketList &sockets, in_port_t port,
457 					int &error,
458 					bool loopback, bool nonblocking,
459 					int family, int socktype, int protocol,
460 					int backlog, bool one)
461 {
462 	std::stringstream ssport;
463 
464 	ssport << port;
465 	return ATNetworkTool::CreateServerSockets(sockets, ssport.str().c_str(),
466 						  error,
467 						  loopback, nonblocking,
468 						  family, socktype, protocol,
469 						  backlog, one);
470 }
471 
472 int ATNetworkTool::CreateServerSockets(ATSocketList &sockets, const char *port,
473 					int &error,
474 					bool loopback, bool nonblocking,
475 					int family, int socktype, int protocol,
476 					int backlog, bool one)
477 {
478 	struct addrinfo hints, *paddr, *paddrp;
479 	int num = 0;
480 
481 	memset(&hints, 0, sizeof(hints));
482 	if (ATNetworkTool::AF_XINETX == family) {
483 		hints.ai_family = PF_UNSPEC;
484 	} else {
485 		hints.ai_family = family;
486 	}
487 	hints.ai_socktype = socktype;
488 	hints.ai_protocol = protocol;
489 #ifdef AI_NUMERICSERV
490 	hints.ai_flags   |= AI_NUMERICSERV;
491 #endif
492 	if (!loopback) {
493 		hints.ai_flags |= AI_PASSIVE;
494 	}
495 	if ((error = getaddrinfo(NULL, port, &hints, &paddrp)) != 0) {
496 		return -1;
497 	}
498 	for (paddr = paddrp; paddr; paddr = paddr->ai_next) {
499 		if (ATNetworkTool::AF_XINETX == family) {
500 			if (!ATAddress::saIsInet(paddr->ai_addr)) {
501 				continue;
502 			}
503 		}
504 
505 		int s = ATNetworkTool::CreateServerSocket(paddr, error,
506 							  nonblocking,
507 							  backlog);
508 		if (s < 0) {
509 			continue;
510 		}
511 		sockets.push_back(s);
512 		num++;
513 		if (one) {
514 			break;
515 		}
516 	}
517 	freeaddrinfo(paddrp);
518 	return num;
519 }
520 
521 int ATNetworkTool::CreateServerSocket(const struct addrinfo *addr, int &error,
522 					bool nonblocking, int backlog)
523 {
524 	int s = ATNetworkTool::CreateSocket(addr, error);
525 	if (s < 0) {
526 		return -1;
527 	}
528 
529 	if (nonblocking) {
530 		ATNetworkTool::SetNonBlocking(s);
531 	}
532 
533 	if (listen(s, backlog) == -1) {
534 		error = errno;
535 		ATNetworkTool::CloseSocket(s);
536 		return -1;
537 	}
538 
539 	return s;
540 }
541 
542 int ATNetworkTool::SetNonBlocking(int s, bool block)
543 {
544 	if (block) {
545 		return fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);
546 	} else {
547 		return fcntl(s, F_SETFL, fcntl(s, F_GETFL) & ~O_NONBLOCK);
548 	}
549 }
550 
551 int ATNetworkTool::ConnectToSocket(int sock, int &error, bool loopback,
552 				    int socktype, int protocol)
553 {
554 	struct sockaddr_storage ss;
555 	socklen_t addrLen = sizeof(ss);
556 	struct sockaddr *sa = (struct sockaddr *)&ss;
557 
558 	if (getsockname(sock, sa, &addrLen) != 0) {
559 		error = errno;
560 		return -1;
561 	}
562 	int s = ATNetworkTool::ConnectSocket(sa, addrLen,
563 					     error, loopback,
564 					     sa->sa_family,
565 					     socktype, protocol);
566 	if (s < 0) {
567 		return -1;
568 	}
569 	return s;
570 }
571 
572 int ATNetworkTool::Connect(const char *host, in_port_t port,
573 				int &error,
574 				int family, int socktype, int protocol)
575 {
576 	std::stringstream ssport;
577 
578 	ssport << port;
579 
580 	return ATNetworkTool::Connect(host, ssport.str().c_str(), error,
581 					family, socktype, protocol);
582 }
583 
584 int ATNetworkTool::Connect(const char *host, const char *port,
585 				int &error,
586 				int family, int socktype, int protocol)
587 {
588 	struct addrinfo hints, *paddr, *paddrp;
589 	int oks = -1;
590 
591 	if (socktype != SOCK_DGRAM) {
592 		socktype = SOCK_STREAM;
593 	}
594 
595 	memset(&hints, 0, sizeof(hints));
596 	if (ATNetworkTool::AF_XINETX == family) {
597 		hints.ai_family = PF_UNSPEC;
598 	} else {
599 		hints.ai_family = family;
600 	}
601 	hints.ai_socktype = socktype;
602 	hints.ai_protocol = protocol;
603 	hints.ai_flags    = AI_NUMERICHOST;
604 #ifdef AI_NUMERICSERV
605 	hints.ai_flags   |= AI_NUMERICSERV;
606 #endif
607 	if ((error = getaddrinfo(host, port, &hints, &paddrp)) != 0) {
608 		memset(&hints, 0, sizeof(hints));
609 		if (ATNetworkTool::AF_XINETX == family) {
610 			hints.ai_family = PF_UNSPEC;
611 		} else {
612 			hints.ai_family = family;
613 		}
614 		hints.ai_socktype = socktype;
615 		hints.ai_protocol = protocol;
616 #ifdef AI_NUMERICSERV
617 		hints.ai_flags   |= AI_NUMERICSERV;
618 #endif
619 		if ((error = getaddrinfo(host, port, &hints, &paddrp)) != 0) {
620 			return -1;
621 		}
622 	}
623 	for (paddr = paddrp; paddr; paddr = paddr->ai_next) {
624 		if (ATNetworkTool::AF_XINETX == family) {
625 			if (!ATAddress::saIsInet(paddr->ai_addr)) {
626 				continue;
627 			}
628 		}
629 
630 		int s = ATNetworkTool::ConnectSocket(paddr, error);
631 		if (s < 0) {
632 			continue;
633 		}
634 		oks = s;
635 		break;
636 	}
637 	freeaddrinfo(paddrp);
638 	return oks;
639 }
640 
641 int ATNetworkTool::ConnectLoopback(in_port_t port,
642 				int &error,
643 				int family, int socktype, int protocol)
644 {
645 	std::stringstream ssport;
646 
647 	ssport << port;
648 
649 	return ATNetworkTool::ConnectLoopback(ssport.str().c_str(), error,
650 					family, socktype, protocol);
651 }
652 
653 int ATNetworkTool::ConnectLoopback(const char *port,
654 				int &error,
655 				int family, int socktype, int protocol)
656 {
657 	struct addrinfo hints, *paddr, *paddrp;
658 	int oks = -1;
659 
660 	if (socktype != SOCK_DGRAM) {
661 		socktype = SOCK_STREAM;
662 	}
663 
664 	memset(&hints, 0, sizeof(hints));
665 	if (ATNetworkTool::AF_XINETX == family) {
666 		hints.ai_family = PF_UNSPEC;
667 	} else {
668 		hints.ai_family = family;
669 	}
670 	hints.ai_socktype = socktype;
671 	hints.ai_protocol = protocol;
672 #ifdef AI_NUMERICSERV
673 	hints.ai_flags   |= AI_NUMERICSERV;
674 #endif
675 	if ((error = getaddrinfo(NULL, port, &hints, &paddrp)) != 0) {
676 		return -1;
677 	}
678 	for (paddr = paddrp; paddr; paddr = paddr->ai_next) {
679 		if (ATNetworkTool::AF_XINETX == family) {
680 			if (!ATAddress::saIsInet(paddr->ai_addr)) {
681 				continue;
682 			}
683 		}
684 
685 		int s = ATNetworkTool::ConnectSocket(paddr, error, true);
686 		if (s < 0) {
687 			continue;
688 		}
689 		oks = s;
690 		break;
691 	}
692 	freeaddrinfo(paddrp);
693 	return oks;
694 }
695 
696 unsigned int ATNetworkTool::GetLocalPort(int sock)
697 {
698 	struct sockaddr_storage ss;
699 	socklen_t addrLen = sizeof(ss);
700 	struct sockaddr *sa = (struct sockaddr *)&ss;
701 
702 	if (getsockname(sock, sa, &addrLen) != 0) {
703 		return 0;
704 	}
705 	switch (sa->sa_family) {
706 	case AF_INET6:
707 		return ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
708 		break;
709 	case AF_INET:
710 		return ntohs(((struct sockaddr_in *)sa)->sin_port);
711 		break;
712 	}
713 	return 0;
714 }
715 
716 int ATNetworkTool::Accept(int s, ATAddress &address,
717 			  int &error, bool nonblocking)
718 {
719 	struct sockaddr_storage saddr;
720 	socklen_t addrLen = sizeof(saddr);
721 	struct sockaddr *addr = (struct sockaddr *)&saddr;
722 
723 	int s_new = accept(s, addr, &addrLen);
724 	if (s_new == -1) {
725 		error = errno;
726 		return -1;
727 	}
728 
729 	address = addr;
730 
731 	ATNetworkTool::SetNonBlocking(s_new, nonblocking);
732 
733 	return s_new;
734 }
735 
736