#include <linux/if_tun.h>
#endif
-#include <getopt.h>
-
-#ifdef HAVE_MINGW
-#include <pthread.h>
-#endif
-
#include "crypto.h"
#include "ecdsa.h"
#include "meta.h"
#include "sptps.h"
#include "utils.h"
#include "names.h"
+#include "random.h"
-#ifndef HAVE_MINGW
+#ifndef HAVE_WINDOWS
#define closesocket(s) close(s)
#endif
static bool send_data(void *handle, uint8_t type, const void *data, size_t len) {
(void)type;
- char hex[len * 2 + 1];
+ char *hex = alloca(len * 2 + 1);
bin2hex(data, hex, len);
if(verbose) {
return true;
}
+typedef enum option_t {
+ OPT_BAD_OPTION = '?',
+ OPT_LONG_OPTION = 0,
+
+ // Short options
+ OPT_DATAGRAM = 'd',
+ OPT_QUIT_ON_EOF = 'q',
+ OPT_READONLY = 'r',
+ OPT_WRITEONLY = 'w',
+ OPT_PACKET_LOSS = 'L',
+ OPT_REPLAY_WINDOW = 'W',
+ OPT_SPECIAL_CHAR = 's',
+ OPT_TUN = 't',
+ OPT_VERBOSE = 'v',
+ OPT_IPV4 = '4',
+ OPT_IPV6 = '6',
+
+ // Long options
+ OPT_HELP = 255,
+} option_t;
+
static struct option const long_options[] = {
- {"datagram", no_argument, NULL, 'd'},
- {"quit", no_argument, NULL, 'q'},
- {"readonly", no_argument, NULL, 'r'},
- {"writeonly", no_argument, NULL, 'w'},
- {"packet-loss", required_argument, NULL, 'L'},
- {"replay-window", required_argument, NULL, 'W'},
- {"special", no_argument, NULL, 's'},
- {"verbose", required_argument, NULL, 'v'},
- {"help", no_argument, NULL, 1},
- {NULL, 0, NULL, 0}
+ {"datagram", no_argument, NULL, OPT_DATAGRAM},
+ {"quit", no_argument, NULL, OPT_QUIT_ON_EOF},
+ {"readonly", no_argument, NULL, OPT_READONLY},
+ {"writeonly", no_argument, NULL, OPT_WRITEONLY},
+ {"packet-loss", required_argument, NULL, OPT_PACKET_LOSS},
+ {"replay-window", required_argument, NULL, OPT_REPLAY_WINDOW},
+ {"special", no_argument, NULL, OPT_SPECIAL_CHAR},
+ {"tun", no_argument, NULL, OPT_TUN},
+ {"verbose", required_argument, NULL, OPT_VERBOSE},
+ {"help", no_argument, NULL, OPT_HELP},
+ {NULL, 0, NULL, 0}
};
static void usage(void) {
- static const char *message =
+ fprintf(stderr,
"Usage: %s [options] my_ed25519_key_file his_ed25519_key_file [host] port\n"
"\n"
"Valid options are:\n"
" -4 Use IPv4.\n"
" -6 Use IPv6.\n"
"\n"
- "Report bugs to tinc@tinc-vpn.org.\n";
-
- fprintf(stderr, message, program_name);
+ "Report bugs to tinc@tinc-vpn.org.\n",
+ program_name);
}
-#ifdef HAVE_MINGW
+#ifdef HAVE_WINDOWS
int stdin_sock_fd = -1;
// separate thread between the stdin and the sptps loop way below. This thread
// reads stdin and sends its content to the main thread through a TCP socket,
// which can be properly select()'ed.
-static void *stdin_reader_thread(void *arg) {
+static DWORD WINAPI stdin_reader_thread(LPVOID arg) {
struct sockaddr_in sa;
socklen_t sa_size = sizeof(sa);
closesocket(stdin_sock_fd);
stdin_sock_fd = -1;
- return NULL;
+ return 0;
}
static int start_input_reader(void) {
fprintf(stderr, "stdin thread is listening on :%d\n", ntohs(connect_sa.sin_port));
}
- pthread_t th;
- int err = pthread_create(&th, NULL, stdin_reader_thread, NULL);
-
- if(err) {
- fprintf(stderr, "Could not start reader thread: %s\n", strerror(err));
+ if(!CreateThread(NULL, 0, stdin_reader_thread, NULL, 0, NULL)) {
+ fprintf(stderr, "Could not start reader thread: %d\n", GetLastError());
goto server_err;
}
return -1;
}
-#endif // HAVE_MINGW
+#endif // HAVE_WINDOWS
-int main(int argc, char *argv[]) {
+static void print_listening_msg(int sock) {
+ sockaddr_t sa = {0};
+ socklen_t salen = sizeof(sa);
+ int port = 0;
+
+ if(!getsockname(sock, &sa.sa, &salen)) {
+ port = ntohs(sa.in.sin_port);
+ }
+
+ fprintf(stderr, "Listening on %d...\n", port);
+ fflush(stderr);
+}
+
+static int run_test(int argc, char *argv[]) {
program_name = argv[0];
bool initiator = false;
bool datagram = false;
bool quit = false;
while((r = getopt_long(argc, argv, "dqrstwL:W:v46", long_options, &option_index)) != EOF) {
- switch(r) {
- case 0: /* long option */
+ switch((option_t) r) {
+ case OPT_LONG_OPTION:
break;
- case 'd': /* datagram mode */
+ case OPT_BAD_OPTION:
+ usage();
+ return 1;
+
+ case OPT_DATAGRAM:
datagram = true;
break;
- case 'q': /* close connection on EOF from stdin */
+ case OPT_QUIT_ON_EOF:
quit = true;
break;
- case 'r': /* read only */
+ case OPT_READONLY:
readonly = true;
break;
- case 't': /* read only */
+ case OPT_TUN:
#ifdef HAVE_LINUX
tun = true;
#else
#endif
break;
- case 'w': /* write only */
+ case OPT_WRITEONLY:
writeonly = true;
break;
- case 'L': /* packet loss rate */
+ case OPT_PACKET_LOSS:
packetloss = atoi(optarg);
break;
- case 'W': /* replay window size */
+ case OPT_REPLAY_WINDOW:
sptps_replaywin = atoi(optarg);
break;
- case 'v': /* be verbose */
+ case OPT_VERBOSE:
verbose = true;
break;
- case 's': /* special character handling */
+ case OPT_SPECIAL_CHAR:
special = true;
break;
- case '?': /* wrong options */
- usage();
- return 1;
-
- case '4': /* IPv4 */
+ case OPT_IPV4:
addressfamily = AF_INET;
break;
- case '6': /* IPv6 */
+ case OPT_IPV6:
addressfamily = AF_INET6;
break;
- case 1: /* help */
+ case OPT_HELP:
usage();
return 0;
#endif
-#ifdef HAVE_MINGW
+#ifdef HAVE_WINDOWS
static struct WSAData wsa_state;
if(WSAStartup(MAKEWORD(2, 2), &wsa_state)) {
return 1;
}
- fprintf(stderr, "Listening...\n");
+ print_listening_msg(sock);
sock = accept(sock, NULL, NULL);
return 1;
}
} else {
- fprintf(stderr, "Listening...\n");
+ print_listening_msg(sock);
char buf[65536];
struct sockaddr addr;
fprintf(stderr, "Connected\n");
}
- crypto_init();
- prng_init();
-
FILE *fp = fopen(argv[1], "r");
if(!fp) {
if(!fp) {
fprintf(stderr, "Could not open %s: %s\n", argv[2], strerror(errno));
- free(mykey);
+ ecdsa_free(mykey);
return 1;
}
ecdsa_t *hiskey = NULL;
if(!(hiskey = ecdsa_read_pem_public_key(fp))) {
- free(mykey);
+ ecdsa_free(mykey);
return 1;
}
sptps_t s;
if(!sptps_start(&s, &sock, initiator, datagram, mykey, hiskey, "sptps_test", 10, send_data, receive_record)) {
- free(mykey);
- free(hiskey);
+ ecdsa_free(mykey);
+ ecdsa_free(hiskey);
return 1;
}
-#ifdef HAVE_MINGW
+#ifdef HAVE_WINDOWS
if(!readonly) {
in = start_input_reader();
if(in < 0) {
fprintf(stderr, "Could not init stdin reader thread\n");
- free(mykey);
- free(hiskey);
+ ecdsa_free(mykey);
+ ecdsa_free(hiskey);
return 1;
}
}
FD_SET(sock, &fds);
if(select(max_fd + 1, &fds, NULL, NULL, NULL) <= 0) {
- free(mykey);
- free(hiskey);
+ ecdsa_free(mykey);
+ ecdsa_free(hiskey);
return 1;
}
if(FD_ISSET(in, &fds)) {
-#ifdef HAVE_MINGW
+#ifdef HAVE_WINDOWS
ssize_t len = recv(in, buf, readsize, 0);
#else
ssize_t len = read(in, buf, readsize);
if(len < 0) {
fprintf(stderr, "Could not read from stdin: %s\n", strerror(errno));
- free(mykey);
- free(hiskey);
+ ecdsa_free(mykey);
+ ecdsa_free(hiskey);
return 1;
}
if(len == 0) {
-#ifdef HAVE_MINGW
+#ifdef HAVE_WINDOWS
shutdown(in, SD_SEND);
closesocket(in);
#endif
sptps_send_record(&s, 0, buf, len);
}
} else if(!sptps_send_record(&s, buf[0] == '!' ? 1 : 0, buf, (len == 1 && buf[0] == '\n') ? 0 : buf[0] == '*' ? sizeof(buf) : (size_t)len)) {
- free(mykey);
- free(hiskey);
+ ecdsa_free(mykey);
+ ecdsa_free(hiskey);
return 1;
}
}
if(len < 0) {
fprintf(stderr, "Could not read from socket: %s\n", sockstrerror(sockerrno));
- free(mykey);
- free(hiskey);
+ ecdsa_free(mykey);
+ ecdsa_free(hiskey);
return 1;
}
}
if(verbose) {
- char hex[len * 2 + 1];
+ char *hex = alloca(len * 2 + 1);
bin2hex(buf, hex, len);
fprintf(stderr, "Received %ld bytes of data:\n%s\n", (long)len, hex);
}
if(!done) {
if(!datagram) {
- free(mykey);
- free(hiskey);
+ ecdsa_free(mykey);
+ ecdsa_free(hiskey);
return 1;
}
}
bool stopped = sptps_stop(&s);
- free(mykey);
- free(hiskey);
+ ecdsa_free(mykey);
+ ecdsa_free(hiskey);
+ closesocket(sock);
- if(!stopped) {
- return 1;
- }
+ return !stopped;
+}
- closesocket(sock);
+int main(int argc, char *argv[]) {
+ random_init();
+ crypto_init();
+ prng_init();
- return 0;
+ int result = run_test(argc, argv);
+
+ random_exit();
+
+ return result;
}