summaryrefslogtreecommitdiffstats
path: root/src/net-proxy-udp.c
blob: 996b79366d5b8223d643ffb7cc40664bf56b2052 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#include "intf.h"
#include "net-proxy.h"
#include "debug.h"

static int init_fd(struct tsnif_handle *h, struct tsnif_np_args *args, int server)
{
	struct tsnif_np_handle *nph = &h->np;
	struct sockaddr_in sa;
	int fd;

	fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
	if (-1 == fd) {
		TSNIF_DEBUG(NP, "failed to create udp socket\n");
		return -1;
	}

	nph->fd_udp = fd;

	if (server) {
		memset((char *) &sa, 0, sizeof(sa));
		sa.sin_family = AF_INET;
		sa.sin_port = htons(args->port);
		/* XXX finish given host resolving */
		sa.sin_addr.s_addr = htonl(INADDR_ANY);

		if (-1 == bind(fd, &sa, sizeof(sa))) {
			close(fd);
			TSNIF_DEBUG(NP, "failed to bind to %d\n", args->port);
			return -1;
		}
	}

	TSNIF_DEBUG(NP, "socket created %d\n", fd);
	return 0;
}

int udp_init_server(struct tsnif_handle *h, struct tsnif_np_args *args)
{
	TSNIF_DEBUG(NP, "creating server socket\n");
	return init_fd(h, args, 1);
}

int udp_init_client(struct tsnif_handle *h, struct tsnif_np_args *args)
{
	TSNIF_DEBUG(NP, "creating client socket\n");
	return init_fd(h, args, 0);
}

int udp_close(struct tsnif_handle *h)
{
	struct tsnif_np_handle *nph = &h->np;

	TSNIF_DEBUG(NP, "closing client socket\n");
	close(nph->fd_udp);
	return 0;
}

int udp_send(struct tsnif_handle *h, struct trans_msg *msg)
{
	struct tsnif_np_msg *m;
	struct tsnif_np_handle *nph = &h->np;
	int size = sizeof(*msg);

	TSNIF_DEBUG(NP, "sending cmd = %d\n", msg->cmd);

	if (TSNIF_CMD_DATA == msg->cmd)
		size += msg->data.len;

	m = malloc(size);
	if (!m)
		return -1;

	m->msg = *msg;

	if (TSNIF_CMD_DATA == msg->cmd)
		memcpy(m->data, msg->data.ptr, msg->data.len);

	if (TSNIF_NP_UDP_SERVER & nph->flags)
		return sendto(nph->fd_udp, m, size, 0,
			      &nph->udp_client.sa, sizeof(nph->udp_client.sa));

	return send(nph->fd_udp, m, size, 0);
}

int udp_process(struct tsnif_handle *h)
{
	struct tsnif_np_handle *nph = &h->np;
	struct trans_msg msg;
	char *data = NULL;
	int ret;
	struct sockaddr_in sa;
	socklen_t sl = sizeof(sa);

	ret = recvfrom(nph->fd_udp, &msg, sizeof(msg), 0,
		       &sa, &sl);
	if (ret <= 0)
		return ret;

	/* just one client supported for now */
	if (memcmp(&nph->udp_client.sa, &sa, sizeof(sa))) {
		TSNIF_DEBUG(NP, "got new client\n");
		memset(&nph->udp_client, 0x0, sizeof(nph->udp_client));
		nph->udp_client.sa = sa;
		nph->udp_client.connected = 1;
	}

	/* receive the data part */
	if (TSNIF_CMD_DATA == msg.cmd) {

		/* XXX some size check would be nice.. */
		data = malloc(msg.data.len);
		if (!data)
			return -1;

		ret = recvfrom(nph->fd_udp, data, msg.data.len, 0,
			       &sa, &sl);
		if (ret <= 0) {
			free(data);
			return ret;
		}

		msg.data.ptr = data;
	}

	ret = tsnif_np_dispatch(h, &msg);

	if (data)
		free(data);

	return ret;
}

struct tsnif_np_prot udp_prot = {
	.init_server = udp_init_server,
	.init_client = udp_init_client,
	.close       = udp_close,
	.send        = udp_send,
	.process     = udp_process,
};