blob: c79bf7fd7f7c9380eeccc7a5fd10ff518b12e91a [file] [log] [blame] [edit]
//
// Copyright 2018 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#import "Channel/Sources/EDOSocketPort.h"
#include <arpa/inet.h>
#include <sys/un.h>
/** Gets the socket port from the given socket address struct. */
static UInt16 GetSocketPort(const struct sockaddr_storage *socketAddress) {
if (socketAddress->ss_family == AF_INET) {
return ntohs(((const struct sockaddr_in *)socketAddress)->sin_port);
} else if (socketAddress->ss_family == AF_INET6) {
return ntohs(((const struct sockaddr_in6 *)socketAddress)->sin6_port);
} else {
return 0;
}
}
/** Gets the IP address from the given socket address struct. */
static NSString *GetSocketIPAddress(const struct sockaddr_storage *socketAddress) {
if (socketAddress->ss_family == AF_INET) {
char addressBuf[INET_ADDRSTRLEN];
const struct sockaddr_in *addrIPv4 = (const struct sockaddr_in *)socketAddress;
inet_ntop(AF_INET, &addrIPv4->sin_addr, addressBuf, sizeof(addressBuf));
return [NSString stringWithUTF8String:addressBuf];
} else if (socketAddress->ss_family == AF_INET6) {
char addressBuf[INET6_ADDRSTRLEN];
const struct sockaddr_in6 *addrIPv6 = (const struct sockaddr_in6 *)socketAddress;
inet_ntop(AF_INET6, &addrIPv6->sin6_addr, addressBuf, sizeof(addressBuf));
return [NSString stringWithUTF8String:addressBuf];
} else {
return nil;
}
}
@implementation EDOSocketPort {
/** The raw socket address storage. */
struct sockaddr_storage _socketAddress;
/** The raw socket address storage for the connected peer. */
struct sockaddr_storage _peerSocketAddress;
}
- (instancetype)initWithSocket:(dispatch_fd_t)socketFD {
self = [super init];
if (self) {
socklen_t addrLen = sizeof(_socketAddress);
if (getsockname(socketFD, (struct sockaddr *)&_socketAddress, &addrLen) == -1) {
// We ignore the failure and reset to zero, for example, the invalid socket.
memset(&_socketAddress, 0, addrLen);
}
socklen_t peerAddrLen = sizeof(_peerSocketAddress);
if (getpeername(socketFD, (struct sockaddr *)&_peerSocketAddress, &peerAddrLen) == -1) {
// Ignore the failure and reset to zero for invalid sockets.
memset(&_peerSocketAddress, 0, peerAddrLen);
}
}
return self;
}
- (UInt16)port {
return GetSocketPort(&_socketAddress);
}
- (NSString *)IPAddress {
return GetSocketIPAddress(&_socketAddress);
}
- (UInt16)peerPort {
return GetSocketPort(&_peerSocketAddress);
}
- (NSString *)peerIPAddress {
return GetSocketIPAddress(&_peerSocketAddress);
}
- (NSString *)localPath {
if (_peerSocketAddress.ss_family == AF_UNIX) {
struct sockaddr_un *unixSock = (struct sockaddr_un *)&_peerSocketAddress;
return [NSString stringWithUTF8String:unixSock->sun_path];
} else {
return nil;
}
}
- (NSString *)description {
if (self.localPath) {
return [NSString stringWithFormat:@"The socket connects to %@", self.localPath];
} else {
return [NSString stringWithFormat:@"The socket bound on %d at %@, peer on %d at %@", self.port,
self.IPAddress, self.peerPort, self.peerIPAddress];
}
}
@end