#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdlib.h> // call to exit()

#define CONNECTED_PORT 29000
#define EXAMPLE_REMOTE_IP "8.8.8.8"
#define EXAMPLE_REMOTE_PORT 33222

void die(const char * msg) {
	perror(msg);
	exit(1);
}

void grep(int port) {
	char command[64];
	char buffer[256];

	sprintf(command, "lsof | grep -o 'UDP.*%d'", port);
	FILE * output = popen(command, "r");
	printf("  --> Output from lsof | grep -o 'UDP.*%d'\n", port);
	while (fgets(buffer, 256, output) != NULL)
		puts(buffer);
	pclose(output);

	sprintf(command, "netstat -anu | grep %d", port);
	output = popen(command, "r");
	printf("  --> Output from netstat -anu | grep %d\n", port);
	while (fgets(buffer, 256, output) != NULL)
		puts(buffer);
	pclose(output);
}

int main(void) {
	struct sockaddr_in co_sockaddr, remote_sockaddr;
	int co_s;

	memset((char *) &co_sockaddr, 0, sizeof(co_sockaddr));
	memset((char *) &remote_sockaddr, 0, sizeof(remote_sockaddr));

	puts("--> Creating socket");
	if ((co_s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
		die("connected socket()\n");

	co_sockaddr.sin_family = AF_INET;
	co_sockaddr.sin_port = htons(CONNECTED_PORT);
	co_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);

	printf("--> Binding socket to INADDR_ANY:%d (aka *:%d or 0.0.0.0:%d)\n", CONNECTED_PORT, CONNECTED_PORT, CONNECTED_PORT);
	if (bind(co_s, (struct sockaddr *) &co_sockaddr, sizeof(co_sockaddr)) == -1)
		die("connected bind()\n");

	/* At this point, the socket is correctly shown as accepting on all interfaces,
	   as shown by the following output of lsof and netstat */

	grep(CONNECTED_PORT);

	remote_sockaddr.sin_family = AF_INET;
	remote_sockaddr.sin_port = htons(EXAMPLE_REMOTE_PORT);
	if (inet_aton(EXAMPLE_REMOTE_IP, &remote_sockaddr.sin_addr) == 0)
		die("remote inet_aton()\n");

	printf("--> Connecting socket to %s:%d (no data will be sent)\n", EXAMPLE_REMOTE_IP, EXAMPLE_REMOTE_PORT);
	if (connect(co_s, (struct sockaddr *) &remote_sockaddr, sizeof(remote_sockaddr)) == -1)
		die("connect()\n");

	/* Here, the socket is not bound to * or 0.0.0.0 anymore, but to one of the interfaces only. Why?
	   The manual pages for bind() or connect() do not provide any helpful information */

	grep(CONNECTED_PORT);

	close(co_s);
	
}
