http_client_upcall : support IPv4/IPv6 only modes
diff --git a/programs/http_client_upcall.c b/programs/http_client_upcall.c
index a13b4ba..00276f3 100644
--- a/programs/http_client_upcall.c
+++ b/programs/http_client_upcall.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016-2018 Felix Weinrank
+ * Copyright (C) 2016-2019 Felix Weinrank
  *
  * All rights reserved.
  *
@@ -52,6 +52,10 @@
 #endif
 #include <usrsctp.h>
 
+#define RETVAL_CATCHALL     50
+#define RETVAL_ECONNREFUSED 60
+#define RETVAL_TIMEOUT      61
+
 int done = 0;
 int writePending = 1;
 
@@ -65,7 +69,6 @@
 
 #define BUFFERSIZE                 (1<<16)
 
-
 static void handle_upcall(struct socket *sock, void *arg, int flgs)
 {
 	int events = usrsctp_get_events(sock);
@@ -128,19 +131,53 @@
 main(int argc, char *argv[])
 {
 	struct socket *sock;
+	struct sockaddr *addr;
+	socklen_t addr_len;
 	struct sockaddr_in addr4;
 	struct sockaddr_in6 addr6;
+	struct sockaddr_in bind4;
+	struct sockaddr_in6 bind6;
 	struct sctp_udpencaps encaps;
+	struct sctp_sndinfo sndinfo;
 	struct sctp_rtoinfo rtoinfo;
 	struct sctp_initmsg initmsg;
-	int result;
+	int result = 0;
+	uint8_t address_family = 0;
 
 	if (argc < 3) {
 		printf("Usage: http_client_upcall remote_addr remote_port [local_port] [local_encaps_port] [remote_encaps_port] [uri]\n");
 		return(EXIT_FAILURE);
 	}
 
-	result = 0;
+	memset((void *)&addr4, 0, sizeof(struct sockaddr_in));
+	memset((void *)&addr6, 0, sizeof(struct sockaddr_in6));
+
+	if (inet_pton(AF_INET, argv[1], &addr4.sin_addr) == 1) {
+		address_family = AF_INET;
+
+		addr = (struct sockaddr *)&addr4;
+		addr_len = sizeof(addr4);
+#ifdef HAVE_SIN_LEN
+		addr4.sin_len = sizeof(struct sockaddr_in);
+#endif
+		addr4.sin_family = AF_INET;
+		addr4.sin_port = htons(atoi(argv[2]));
+	} else if (inet_pton(AF_INET6, argv[1], &addr6.sin6_addr) == 1) {
+		address_family = AF_INET6;
+
+		addr = (struct sockaddr *)&addr6;
+		addr_len = sizeof(addr6);
+#ifdef HAVE_SIN6_LEN
+		addr6.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+		addr6.sin6_family = AF_INET6;
+		addr6.sin6_port = htons(atoi(argv[2]));
+	} else {
+		printf("Unsupported destination address - use IPv4 or IPv6 address\n");
+		result = RETVAL_CATCHALL;
+		goto out;
+	}
+
 	if (argc > 4) {
 		usrsctp_init(atoi(argv[4]), NULL, debug_printf);
 	} else {
@@ -153,9 +190,9 @@
 
 	usrsctp_sysctl_set_sctp_blackhole(2);
 
-	if ((sock = usrsctp_socket(AF_INET6, SOCK_STREAM, IPPROTO_SCTP, NULL, NULL, 0, NULL)) == NULL) {
+	if ((sock = usrsctp_socket(address_family, SOCK_STREAM, IPPROTO_SCTP, NULL, NULL, 0, NULL)) == NULL) {
 		perror("usrsctp_socket");
-		result = 1;
+		result = RETVAL_CATCHALL;
 		goto out;
 	}
 
@@ -168,7 +205,7 @@
 	if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_RTOINFO, (const void *)&rtoinfo, (socklen_t)sizeof(struct sctp_rtoinfo)) < 0) {
 		perror("setsockopt");
 		usrsctp_close(sock);
-		result = 3;
+		result = RETVAL_CATCHALL;
 		goto out;
 	}
 	initmsg.sinit_num_ostreams = 1;
@@ -178,34 +215,52 @@
 	if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_INITMSG, (const void *)&initmsg, (socklen_t)sizeof(struct sctp_initmsg)) < 0) {
 		perror("setsockopt");
 		usrsctp_close(sock);
-		result = 3;
+		result = RETVAL_CATCHALL;
 		goto out;
 	}
 
 	if (argc > 3) {
-		memset((void *)&addr6, 0, sizeof(struct sockaddr_in6));
+
+		if (address_family == AF_INET) {
+			memset((void *)&bind4, 0, sizeof(struct sockaddr_in));
 #ifdef HAVE_SIN6_LEN
-		addr6.sin6_len = sizeof(struct sockaddr_in6);
+			bind4.sin_len = sizeof(struct sockaddr_in6);
 #endif
-		addr6.sin6_family = AF_INET6;
-		addr6.sin6_port = htons(atoi(argv[3]));
-		addr6.sin6_addr = in6addr_any;
-		if (usrsctp_bind(sock, (struct sockaddr *)&addr6, sizeof(struct sockaddr_in6)) < 0) {
-			perror("bind");
-			usrsctp_close(sock);
-			result = 2;
-			goto out;
+			bind4.sin_family = AF_INET;
+			bind4.sin_port = htons(atoi(argv[3]));
+			bind4.sin_addr.s_addr = htonl(INADDR_ANY);
+
+			if (usrsctp_bind(sock, (struct sockaddr *)&bind4, sizeof(bind4)) < 0) {
+				perror("bind");
+				usrsctp_close(sock);
+				result = RETVAL_CATCHALL;
+				goto out;
+			}
+		} else {
+			memset((void *)&bind6, 0, sizeof(struct sockaddr_in6));
+#ifdef HAVE_SIN6_LEN
+			bind6.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+			bind6.sin6_family = AF_INET6;
+			bind6.sin6_port = htons(atoi(argv[3]));
+			bind6.sin6_addr = in6addr_any;
+			if (usrsctp_bind(sock, (struct sockaddr *)&bind6, sizeof(bind6)) < 0) {
+				perror("bind");
+				usrsctp_close(sock);
+				result = RETVAL_CATCHALL;
+				goto out;
+			}
 		}
 	}
 
 	if (argc > 5) {
 		memset(&encaps, 0, sizeof(struct sctp_udpencaps));
-		encaps.sue_address.ss_family = AF_INET6;
+		encaps.sue_address.ss_family = address_family;
 		encaps.sue_port = htons(atoi(argv[5]));
 		if (usrsctp_setsockopt(sock, IPPROTO_SCTP, SCTP_REMOTE_UDP_ENCAPS_PORT, (const void *)&encaps, (socklen_t)sizeof(struct sctp_udpencaps)) < 0) {
 			perror("setsockopt");
 			usrsctp_close(sock);
-			result = 3;
+			result = RETVAL_CATCHALL;
 			goto out;
 		}
 	}
@@ -224,44 +279,35 @@
 #endif
 	}
 
+	printf("\nHTTP request:\n%s\n", request);
+	printf("\nHTTP response:\n");
+
 	usrsctp_set_upcall(sock, handle_upcall, NULL);
 
-	memset((void *)&addr4, 0, sizeof(struct sockaddr_in));
-	memset((void *)&addr6, 0, sizeof(struct sockaddr_in6));
-#ifdef HAVE_SIN_LEN
-	addr4.sin_len = sizeof(struct sockaddr_in);
-#endif
-#ifdef HAVE_SIN6_LEN
-	addr6.sin6_len = sizeof(struct sockaddr_in6);
-#endif
-	addr4.sin_family = AF_INET;
-	addr6.sin6_family = AF_INET6;
-	addr4.sin_port = htons(atoi(argv[2]));
-	addr6.sin6_port = htons(atoi(argv[2]));
-	if (inet_pton(AF_INET6, argv[1], &addr6.sin6_addr) == 1) {
-		if (usrsctp_connect(sock, (struct sockaddr *)&addr6, sizeof(struct sockaddr_in6)) < 0) {
-			if (errno != EINPROGRESS) {
-				perror("usrsctp_connect");
-				usrsctp_close(sock);
-				result = 4;
-				goto out;
+	if (usrsctp_connect(sock, addr, addr_len) < 0) {
+		if (errno != EINPROGRESS) {
+			perror("usrsctp_connect");
+			usrsctp_close(sock);
+
+			if (errno == ECONNREFUSED) {
+				result = RETVAL_ECONNREFUSED;
+			} else {
+				result = RETVAL_CATCHALL;
 			}
+			goto out;
 		}
-	} else if (inet_pton(AF_INET, argv[1], &addr4.sin_addr) == 1) {
-		if (usrsctp_connect(sock, (struct sockaddr *)&addr4, sizeof(struct sockaddr_in)) < 0) {
-			if (errno != EINPROGRESS) {
-				perror("usrsctp_connect");
-				usrsctp_close(sock);
-				result = 5;
-				goto out;
-			}
-		}
-	} else {
-		printf("Illegal destination address\n");
+	}
+
+	memset(&sndinfo, 0, sizeof(struct sctp_sndinfo));
+	sndinfo.snd_ppid = htonl(63); /* PPID for HTTP/SCTP */
+	/* send GET request */
+	if (usrsctp_sendv(sock, request, strlen(request), NULL, 0, &sndinfo, sizeof(struct sctp_sndinfo), SCTP_SENDV_SNDINFO, 0) < 0) {
+		perror("usrsctp_sendv");
 		usrsctp_close(sock);
-		result = 6;
+		result = RETVAL_CATCHALL;
 		goto out;
 	}
+
 	while (!done) {
 #ifdef _WIN32
 		Sleep(1*1000);