Preparing the Server for a Connection
At the top of your application, include vmci_sockets.h and declare a constant for the socket buffer size. In the example below, BUFSIZE defines the socket buffer size. The number 4096 is a good choice for efficiency on multiple platforms. It is not based on the size of a UDP datagram.
#include "vmci_sockets.h"
#define BUFSIZE 4096
To compile on Windows, you must call the Winsock WSAStartup() function.
err = WSAStartup(versionRequested, &wsaData);
if (err != 0) {
printf(stderr, "Could not register with Winsock DLL.\n");
goto exit;
}
This is not necessary on non-Windows systems.
Socket() Function
To alter a UDP socket program for VMCI sockets, obtain the new address family to replace AF_INET.
int afVMCI = VMCISock_GetAFValue();
if ((sockfd_dgram = socket(afVMCI, SOCK_DGRAM, 0)) == -1) {
perror("socket");
goto exit;
}
VMCISock_GetAFValue() returns a descriptor for the VMCI sockets address family if available.
This call is similar to the one for stream sockets, but has SOCK_DGRAM instead of SOCK_STREAM.
Socket Options
Currently VMCI sockets offers no options for datagram connections.
Bind() Function
The bind() call associates the datagram socket with the network settings in the sockaddr_vm structure, instead of the sockaddr_in structure.
struct sockaddr_vm my_addr = {0};
my_addr.svm_family = afVMCI;
my_addr.svm_cid = VMADDR_CID_ANY;
my_addr.svm_port = VMADDR_PORT_ANY;
if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof my_addr) == -1) {
perror("bind");
goto close;
}
The sockaddr_vm structure contains an element for the context ID (CID) to specify the virtual machine. For the client (connector) this is the local CID. For the server (listener), it could be any connecting virtual machine. VMADDR_CID_ANY and VMADDR_PORT_ANY are predefined so that at bind or connection time, the appropriate CID and port number are filled in from the client. VMADDR_CID_ANY is replaced with the CID of the virtual machine and VMADDR_PORT_ANY provides an ephemeral port from the nonreserved range (>= 1024).
The client (connector) can obtain its local CID by calling VMCISock_GetLocalCID().
The VMCI sockets bind() function is the same as for a UDP datagram application.
Getsockname() Function
The getsockname() function retrieves the local address associated with a socket.
my_addr_size = sizeof my_addr;
if (getsockname(sockfd, (struct sockaddr *) &my_addr, &my_addr_size) == -1) {
perror("getsockname");
goto close;
}
Recvfrom() Function
The recvfrom() call reads data from the client application. Server and client can communicate the length of data transmitted, or the server can terminate its recvfrom() loop when the client closes its connection.
if ((numbytes = recvfrom(sockfd, buf, sizeof buf, 0,
(struct sockaddr *) &their_addr, &my_addr_size)) == -1) {
perror("recvfrom");
goto close;
}
Sendto() Function
The sendto() call optionally writes data back to the client application. See Sendto() Function.
Close() Function
The close() call shuts down transmission, given the original socket descriptor obtained from the socket() call. Some server applications close immediately after receiving client data, while others wait for additional connections. To compile on Windows, you must call the Winsock closesocket() instead of close().
#ifdef _WIN32
return closesocket(sockfd);
#else
return close(sockfd);
#endif