Unnamed unix domain socket has wrong address length - c

When reading the address of a sending unix datagram domain socket in this minimal example program, I am getting an address length of 0, but the man page for unix domain sockets specifies that:
unnamed: A stream socket that has not been bound to a pathname using
bind(2) has no name. Likewise, the two sockets created by socketā€
pair(2) are unnamed. When the address of an unnamed socket is
returned, its length is sizeof(sa_family_t), and sun_path should not
be inspected.
I was expecting the address length of an unnamed socket to be 2 based on this man page. Am I misinterpreting the man page, does the man page not apply to unix sockets of type SOCK_DGRAM or am I simply reading the length incorrectly?
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/un.h>
const char SOCK_NAME[] = { 0, 't', 'e', 's', 't' };
// or for pathnamed socket
// const char SOCK_NAME[] = "/tmp/test.uds";
const char PAYLOAD[] = "Hello!";
int main() {
int rx_sock = socket(AF_UNIX, SOCK_DGRAM, 0);
if (rx_sock < 0) {
perror("Create RX");
exit(1);
}
int tx_sock = socket(AF_UNIX, SOCK_DGRAM, 0);
if (tx_sock < 0) {
perror("Create TX");
exit(1);
}
struct sockaddr_un bind_addr;
bind_addr.sun_family = AF_UNIX;
memcpy(bind_addr.sun_path, SOCK_NAME, sizeof(SOCK_NAME));
socklen_t bind_len = sizeof(sa_family_t) + sizeof(SOCK_NAME);
if (bind(rx_sock, (const struct sockaddr *)&bind_addr, bind_len) != 0) {
perror("Bind RX");
exit(1);
}
if (sendto(tx_sock, PAYLOAD, sizeof(PAYLOAD), 0, (const struct sockaddr *)&bind_addr, bind_len) < 0) {
perror("Sendto");
exit(1);
}
// For pathnamed socket
// unlink(SOCK_NAME);
struct sockaddr_un recv_addr;
socklen_t recv_len = sizeof(recv_addr);
char buffer[1024];
ssize_t rx_count = recvfrom(rx_sock, buffer, sizeof(buffer), 0, (struct sockaddr *)&recv_addr, &recv_len);
if (rx_count < 0) {
perror("Recvfrom");
exit(1);
}
printf("Address size of TX on receiver side: %d\n", recv_len); // 0
recv_len = sizeof(recv_addr);
if (getsockname(tx_sock, (struct sockaddr *)&recv_addr, &recv_len) != 0) {
perror("getsockname");
exit(1);
}
printf("Address size of TX on sender side: %d\n", recv_len); // 2
}

You have an unnamed unbound Unix domain datagram socket tx_sock, and an Unix domain datagram socket rx_sock bound to an abstract address in bind_path.
Note: According to man 7 unix, unbound Unix domain stream sockets are unnamed in Linux, and their address lengths will be sizeof (sa_family_t). According to POSIX.1, unbound socket addresses are unspecified, so we really need to be careful about what we expect of unbound socket addresses and their lengths. In this particular case, in Linux, using the man page as a guide, an unbound Unix domain datagram socket has no address, so its length is zero. (It even makes sense: zero address length indicates you cannot reply to the sender. With an unbound stream socket, there is a connection back to the sender, but no other way to reply to the sender but the connection itself; that is why in that case the address length is then nonzero, sizeof (sa_family_t).)
Abstract Unix domain socket addresses are a Linux extension; they begin with a NUL byte (\0), and are not visible in the filesystem.
You use sendto(tx_sock, msg, msg_len, 0, bind_path, bind_path_len) to send a message.
You use recvfrom(rx_sock, buffer, sizeof buffer, 0, &recv_addr, &recv_addrlen) to receive the message (with recv_addrlen properly initialized to sizeof recv_addr).
Because tx_sock is not bound to any address, it is unnamed unbound: it has no address, cannot be replied to, and therefore recv_addrlen == 0.
If you add code to bind tx_sock to some other abstract address, you'll receive that address in recv_addr and recv_addrlen.
(I verified this behaviour with a test program using four threads, where each thread sends a message to each other thread, and prints all received messages and where they are from, with both standard addresses and abstract addresses. Everything works as documented.)

Of course you're getting a name length of zero.
The first value in your char array is 0, immediately terminating the string to a length of zero bytes:
const char SOCK_NAME[] = { 0, 't', 'e', 's', 't' };
unnamed: A stream socket that has not been bound to a pathname using bind(2) has no name.
does not apply, because you are using bind() to bind the socket:

Related

bind() function is not executing at all, no output when testing it

I'm learning socket programming in C. I have gotten my server to create a socket that was successful, but when I try to bind my socket to a port nothing happens. No error occurs and it is not successful. It's as if the bind() function is not even executing at all.
I've checked out the documentation on the bind() function here but there's no mention of why it won't execute at all. I've also tried searching through this site with no avail.
I also tried following this tutorial from start to finish but the error (or lack thereof) still occurs.
Here is my full code leading up to the problem:
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "include.h"
int main() {
// Descriptors. Used to check the status of functions such as socket, listen, bind etc.
// If a descriptor is equal to 0, then everything is okay. Else, if they are equal to -1, something went wrong.
int socketDescriptor, newSocketDescriptor = 1;
// The process ID of a child process (the client) when a new one is spawned (the client connects).
pid_t childPID;
// A string to hold the commands being sent a received.
char* commandBuffer = calloc(BUFFER_SIZE, sizeof(char));
// A structure to hold information on the server address.
struct sockaddr_in serverAddress;
memset(&serverAddress, '\0', sizeof(serverAddress));
// Fill in the server address information.
// Set the address family to AF_INET, which specifies we will be using IPv4.
// htons() takes the given int and converts it to the appropriate format. Used for port numbers.
// inet_addr() takes the given string and converts it to the appropriate format. Used for IP addresses.
serverAddress.sin_family = AF_INET;
serverAddress.sin_port = htons(PORT);
serverAddress.sin_addr.s_addr = inet_addr("127.0.0.1");
// A structure to hold information a client when a new one connects to this server.
struct sockaddr_in clientAddress;
memset(&clientAddress, '\0', sizeof(clientAddress));
// socklen_t defines the length of a socket structure. Need this for the accept() function.
socklen_t addressSize;
// Creating the socket.
// AF_NET specifies that we will be using IPv4 addressing.
// SOCK_STREAM specifies that we will be using TCP to communicate.
socketDescriptor = socket(AF_INET, SOCK_STREAM, 0);
if (socketDescriptor < 0) {
perror("ERROR CREATING SOCKET");
exit(1);
}
else
printf("Socket created successfully.\n");
// Binding to the specified port. 0 if everything is fine, -1 if there was an error.
if (bind(socketDescriptor, (struct sockaddr*) & serverAddress, sizeof(struct sockaddr_in)) < 0) {
perror("ERROR BINDNING");
exit(1);
}
else
printf("Socket bound to %s:%s.\n", serverAddress.sin_addr.s_addr, serverAddress.sin_port);
The last if statement at the bottom is where the code fails. It should either print and error or print "Socket bound to 127.0.0.1:80" but neither happens. See an example here.
I'm lost for what to do.
A server socket won't show up in a netstat listing unless you call listen after binding the socket.
Also, you're using the %s format specifier in your printf after the bind call on serverAddress.sin_addr.s_addr and serverAddress.sin_port. These are not strings but integers. Using the wrong format specifier invokes undefined behavior and is likely causing your program to crash. Using the correct format specifier such as %d or %x will fix this.
if (bind(socketDescriptor, (struct sockaddr*)&serverAddress, sizeof(struct sockaddr_in)) < 0) {
perror("ERROR BINDNING");
exit(1);
}
else
// use %x to print instead
printf("Socket bound to %x:%x.\n", serverAddress.sin_addr.s_addr, serverAddress.sin_port);
if (listen(socketDescriptor, 3) < 0) {
perror("listen failed");
} else {
printf("socket is listening\n");
}

why the sendto function needs the third parameter, in socket programming

I was new to socket program.
When learning the sendto function, as the prototype:
ssize_t sendto(int socket, const void *message, size_t length,
int flags, const struct sockaddr *dest_addr,
socklen_t dest_len);
I get to know that the "message" has contain the target IP, and the dest_addr argument also specifies the target IP address.
Is there other usage of the dest_addr argument?
I think you are confusing "message" and "dest_addr".
Let's look at the prototype for sendto in expanded form:
ssize_t sendto (int sockfd,
const void *buf,
size_t length,
int flags,
const struct sockaddr *dest_addr,
socklen_t addrlen);
sockfd - this is the socket you created with a call to socket()
buf - this is a pointer to an ARRAY OF BYTES (i.e. they could have made buf of type char* ). That is, this is the data that you want to send across the wire encapsulated in a UDP packet.
length - this is how many bytes are in that array. If you didn't pass "length", it wouldn't know if "buf" was 1 byte or 10000 bytes.
flags - Typically 0. This is advanced stuff
dest_addr - this is a pointer to the destination address. Typically you initialize a sockaddr_in instance and cast its pointer value to a sockaddr* type.
addrlen - the size of the dest_addr. typically, sizeof(sockaddr_in). Address length is variable because dest_addr could pointer to an IPV4 address (sockaddr_in type) or an IPV6 address (sockaddr_in6 type), or some other type.
Example of sending a packet from local port 9999 to remote host "1.2.3.4" on its port 8888. Error checking of return codes left out for brevity.
int s;
sockaddr_in addrDest;
sockaddr_in addrLocal;
char* msg = "Hello World";
// create the socket
s = socket(AF_INET, SOCK_DGRAM, 0); // UDP socket
addrLocal.sin_family = AF_INET;
addrLocal.sin_port = htons(9999);
addrLocal.sin_addr = INADDR_ANY; // zero-init sin_addr to tell it to use all available adapters on the local host
// associate this socket with local UDP port 9999
result = bind(s, (struct sockaddr*)&addrLocal, 0);
// send "Hello world" from local port 9999 to the host at 1.2.3.4 on its port 8888
addrDest.sin_family = AF_INET;
addrDest.sin_port = htons(8888);
addrDest.sin_addr.s_addr = inet_addr("1.2.3.4");
// strlen(msg)+1 for terminating null char
result = sendto(s, msg, strlen(msg)+1, 0, (struct sockaddr*)&addrDest, sizeof(addrDest));
No, Message Contains what you will send, here is an example:
int spatula_count = 3490;
char *secret_message = "The Cheese is in The Toaster";
int stream_socket, dgram_socket;
struct sockaddr_in dest;
int temp;
// first with TCP stream sockets:
// assume sockets are made and connected
//stream_socket = socket(...
//connect(stream_socket, ...
// convert to network byte order
temp = htonl(spatula_count);
// send data normally:
send(stream_socket, &temp, sizeof temp, 0);
// send secret message out of band:
send(stream_socket, secret_message, strlen(secret_message)+1, MSG_OOB);
// now with UDP datagram sockets:
//getaddrinfo(...
//dest = ... // assume "dest" holds the address of the destination
//dgram_socket = socket(...
// send secret message normally:
sendto(dgram_socket, secret_message, strlen(secret_message)+1, 0,
(struct sockaddr*)&dest, sizeof dest);
The message does not contain the destination address, only the payload bytes.
Unless you are using raw sockets... And you should not do that if you are new to socket programming.

Sendto returns -1 and errno 22 (Invalid argument), when set the multicast outgoing interface by ip_mreqn

I faced an issue, when I try to send to multicast group by setting the intended outgoing interface by the code bellow, Actually when the condition is TRUE (if(config.enable_if == 1)) the sendto system call returns error Invalid Argument, but if the condition was False sendto send data and doesn't generate any error.
Please Anyone has an idea, or should I modify anything in my code?
/* Create a datagram socket on which to send. */
sd = socket(AF_INET, SOCK_DGRAM, 0);
/* Set local interface for outbound multicast datagrams. */
/* The IP address specified must be associated with a local */
/* multicast capable interface. */
if(config.enable_if == 1){
mreqn.imr_ifindex = if_nametoindex("eth3");
rc = setsockopt(sd, IPPROTO_IP, IP_MULTICAST_IF, (void *)&mreqn, sizeof(mreqn));
}
/* Initialize the group sockaddr structure with a */
/* group address of dynamic address and port dynamic port. */
memset((char *) &groupSock, 0, sizeof(groupSock));
groupSock.sin_family = AF_INET;
groupSock.sin_addr.s_addr = inet_addr(config.mip);
groupSock.sin_port = htons(config.port);
/* Send a message to the multicast group specified by the*/
/* groupSock sockaddr structure. */
rc = sendto(sd, (const char *)& databuf, datalen, 0, (const struct sockaddr*)&groupSock, sizeof (struct sockaddr));
printf("errno %d\n",errno);
One reason sendto fails is because you pass it a data pointer it does not expect. If you have char* databuf and you then do &databuf you get the address of the pointer, i.e. a pointer to a pointer, of type char**. If you remove the cast (which is not needed) then you will get at least a warning or maybe even an error when compiling.

UDP connect() and recv() on Linux

According to the connect(2) man pages
If the socket sockfd is of type SOCK_DGRAM then serv_addr is the address to which datagrams are sent by default, and the only address from which datagrams are received. If the socket is of type SOCK_STREAM or SOCK_SEQPACKET, this call attempts to make a connection to the socket that is bound to the address specified by serv_addr.
I am trying to filter packets from two different multicast groups that are being broadcasted on the same port and I thought connect() would have done the job but I can't make it work. In facts when I add it to my program I don't receive any packet. More info in this thread.
This is how I set the connect parameters:
memset(&mc_addr, 0, sizeof(mc_addr));
mc_addr.sin_family = AF_INET;
mc_addr.sin_addr.s_addr = inet_addr(multicast_addr);
mc_addr.sin_port = htons(multicast_port);
printf("Connecting...\n");
if( connect(sd, (struct sockaddr*)&mc_addr, sizeof(mc_addr)) < 0 ) {
perror("connect");
return -1;
}
printf("Receiving...\n");
while( (len = recv(sd, msg_buf, sizeof(msg_buf), 0)) > 0 )
printf("Received %d bytes\n", len);
Your program (probably) has the following problems:
you should be using bind() instead of connect(), and
you're missing setsockopt(..., IP_ADD_MEMBERSHIP, ...).
Here's an example program that receives multicasts. It uses recvfrom(), not recv(), but it's the same except you also get the source address for each received packet.
To receive from multiple multicast groups, you have three options.
First option: Use a separate socket for each multicast group, and bind() each socket to a multicast address. This is the simplest option.
Second option: Use a separate socket for each multicast group, bind() each socket INADDR_ANY, and use a socket filter to filter out all but a single multicast group.
Because you've bound to INADDR_ANY, you may still get packets for other multicast groups. It is possible to filter them out using the kernel's socket filters:
#include <stdint.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <linux/filter.h>
/**
* Adds a Linux socket filter to a socket so that only IP
* packets with the given destination IP address will pass.
* dst_addr is in network byte order.
*/
int add_ip_dst_filter (int fd, uint32_t dst_addr)
{
uint16_t hi = ntohl(dst_addr) >> 16;
uint16_t lo = ntohl(dst_addr) & 0xFFFF;
struct sock_filter filter[] = {
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, SKF_NET_OFF + 16), // A <- IP dst high
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, hi, 0, 3), // if A != hi, goto ignore
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, SKF_NET_OFF + 18), // A <- IP dst low
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, lo, 0, 1), // if A != lo, goto ignore
BPF_STMT(BPF_RET + BPF_K, 65535), // accept
BPF_STMT(BPF_RET + BPF_K, 0) // ignore
};
struct sock_fprog fprog = {
.len = sizeof(filter) / sizeof(filter[0]),
.filter = filter
};
return setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog));
}
Third option: use a single socket to receive multicasts for all multicast groups.
In that case, you should do an IP_ADD_MEMBERSHIP for each of the groups. This way you get all packets on a single socket.
However, you need extra code to determine which multicast group a received packet was addressed to. To do that, you have to:
receive packets with recvmsg() and read the IP_PKTINFO or equivalent ancillary data message. However, to make recvmsg() give you this message, you first have to
enable reception of IP_PKTINFO ancillary data messages with setsockopt().
The exact thing you need to do depends on IP protocol version and OS. Here's how I did it (IPv6 code not tested): enabling PKTINFO and reading the option.
Here's a simple program that receives multicasts, which demonstrates the first option (bind to multicast address).
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define MAXBUFSIZE 65536
int main (int argc, char **argv)
{
if (argc != 4) {
printf("Usage: %s <group address> <port> <interface address>\n", argv[0]);
return 1;
}
int sock, status, socklen;
char buffer[MAXBUFSIZE+1];
struct sockaddr_in saddr;
struct ip_mreq imreq;
// set content of struct saddr and imreq to zero
memset(&saddr, 0, sizeof(struct sockaddr_in));
memset(&imreq, 0, sizeof(struct ip_mreq));
// open a UDP socket
sock = socket(PF_INET, SOCK_DGRAM, 0);
if (sock < 0) {
perror("socket failed!");
return 1;
}
// join group
imreq.imr_multiaddr.s_addr = inet_addr(argv[1]);
imreq.imr_interface.s_addr = inet_addr(argv[3]);
status = setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
(const void *)&imreq, sizeof(struct ip_mreq));
saddr.sin_family = PF_INET;
saddr.sin_port = htons(atoi(argv[2]));
saddr.sin_addr.s_addr = inet_addr(argv[1]);
status = bind(sock, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in));
if (status < 0) {
perror("bind failed!");
return 1;
}
// receive packets from socket
while (1) {
socklen = sizeof(saddr);
status = recvfrom(sock, buffer, MAXBUFSIZE, 0, (struct sockaddr *)&saddr, &socklen);
if (status < 0) {
printf("recvfrom failed!\n");
return 1;
}
buffer[status] = '\0';
printf("Received: '%s'\n", buffer);
}
}
The first thing to note is that multicast packets are sent to a multicast address, not from a multicast address.
connect() will allow (or not) packets received from a nominated address.
To configure your socket to receive multicast packets you need to use one of two socket options:
IP_ADD_MEMBERSHIP, or
IP_ADD_SOURCE_MEMBERSHIP
The former allows you to specify a multicast address, the latter allows you to specify a multicast address and source address of the sender.
This can be done using something like the following:
struct ip_mreq groupJoinStruct;
unsigned long groupAddr = inet_addr("239.255.0.1");
groupJoinStruct.imr_multiaddr.s_addr = groupAddr;
groupJoinStruct.imr_interface.s_addr = INADDR_ANY; // or the address of a specific network interface
setsockopt( yourSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &groupJoinStruct );
(error handling omitted for brevity)
To stop receiving multicast packets for this group address, use the socket options:
IP_DROP_MEMBERSHIP, or
IP_DROP_SOURCE_MEMBERSHIP
Note that a socket can have multiple multicast memberships. But, as the multicast address is the destination address of the packet, you need to be able to grab the destination address of the packet to be able to distinguish between packets for different multicast addresses.
To grab the destination address of the packet you'll need to use recvmsg() instead of recv() or recvfrom(). The destination address is contained within the IPPROTO_IP message level, of type DSTADDR_SOCKOPT.
As #Ambroz Bizjak has stated, you'll need to set the IP_PKTINFO socket option to be able to read this information.
Other things to check are:
Is multicast supported in your kernel? Check for the existence of /proc/net/igmp to ensure it's been enabled.
Has multicast been enable on your network interface? Check for "MULTICAST" listed when you run ifconfig on your interface
Does your network interface support multicast? Historically not all have. If not you may be able to get around this by setting your interface to promiscuous mode. e.g. ifconfig eth0 promisc
This should work as long as all the SENDING sockets are bound to the multicast address in question with bind. The address you specify in connect is matched against the SOURCE address of received packets, so you want to ensure that all packets have the same (multicast) SOURCE AND DESTINATION.
bind(2) each socket to the address of the respective multicast group and port instead of INADDR_ANY. That would do the filtering for you.

Are socket options inherited across accept() from the listening socket?

Suppose the listening socket passed to accept has non-default options set on it with setsockopt. Are these options (some or all of them?) inherited by the resulting file descriptors for accepted connections?
Several of the socket options are handled at lower levels of the system. While most of the socket options could be set using the setsockopt. Reference:man setsockopt And since you are mentioning only POSIX on any Linux, in general, as your scope. The accept() (Reference: man accept) does have a certain amount of discretion on what socket options should be inherited and what options to reject from the listening fd.
accept() does not modify the original socket passed to it as argument. The new socket returned by accept() does not inherit file status flags such as O_NONBLOCK,O_ASYNC from the listening socket.
So, instead of relying on the inheritance or non-inheritance of the listening socket properties(which is bound to vary across implementations and licenses), the accepted socket should be explicitly set with the desired socket options.(Best practice)
man pages and the implementation codes in your machine would be the most relevant specification for the accept() behavior.There's no common or standard specification existing across multiple variants of Linux.
No, they're not necessarily inherited. Try this sample, which sets the receive buffer size (SO_RCVBUF) on the initial socket to a non-default value and then compares the result with the inherited socket. Run this code, which listens on TCP port 12345, and then connect to it from any other program.
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
void die(const char *f)
{
printf("%s: %s\n", f, strerror(errno));
exit(1);
}
int main(void)
{
int s = socket(AF_INET, SOCK_STREAM, 0);
if(s < 0)
die("socket");
int rcvbuf;
socklen_t optlen = sizeof(rcvbuf);
if(getsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &optlen) < 0)
die("getsockopt (1)");
printf("initial rcvbuf: %d\n", rcvbuf);
rcvbuf *= 2;
if(setsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)) < 0)
die("setsockopt");
printf("set rcvbuf to %d\n", rcvbuf);
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(12345);
sin.sin_addr.s_addr = INADDR_ANY;
if(bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
die("bind");
if(listen(s, 10) < 0)
die("listen");
struct sockaddr_in client_addr;
socklen_t addr_len = sizeof(client_addr);
int s2 = accept(s, (struct sockaddr *)&client_addr, &addr_len);
if(s2 < 0)
die("accept");
printf("accepted connection\n");
optlen = sizeof(rcvbuf);
if(getsockopt(s2, SOL_SOCKET, SO_RCVBUF, &rcvbuf, &optlen) < 0)
die("getsockopt (2)");
printf("new rcvbuf: %d\n", rcvbuf);
return 0;
}
Result on a machine running Linux 3.0.0-21-generic:
initial rcvbuf: 87380
set rcvbuf to 174760
accepted connection
new rcvbuf: 262142
Socket options is the place where things go that don't fit elsewhere. So, it's expected for different socket options to have different inheriting behaviour. Whether to inherit or not a socket option is decided on a case by case basis.
The answer is No for POSIX conforming implementations, as I read it.
From the POSIX-2017 spec for accept():
The accept() function shall extract the first connection on the queue of pending connections, create a new socket with the same socket type protocol and address family as the specified socket, and allocate a new file descriptor for that socket.
Note it is explicitly a "new socket", not a "full or partial copy of the socket being unqueued", so should have no options different from the default for that socket type and address family. While the copy behavior may be desirable, this is left as an extension interface a platform may have. I haven't seen that any platform does implement one, however, so it could be added to the standard. It is therefore on the application to use getsockopt()/setsockopt() to copy any attributes, that differ from the defaults, from the queue socket to the returned socket, not the responsibility of the interface, before any use of that socket to send or receive data.

Resources