1 /*
2  * Project: udptunnel
3  * File: message.c
4  *
5  * Copyright (C) 2009 Daniel Meekins
6  * Contact: dmeekins - gmail
7  *
8  * This program is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #ifndef WIN32
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #endif /*WIN32*/
29 
30 #include "common.h"
31 #include "message.h"
32 #include "socket.h"
33 
34 /*
35  * Sends a message to the UDP tunnel with the specified client ID, type, and
36  * data. The data can be NULL and data_len 0 if the type of message won't have
37  * a body, based on the protocol.
38  * Returns 0 for success, -1 on error, or -2 to close the connection.
39  */
msg_send_msg(socket_t * to,uint16_t client_id,uint8_t type,char * data,int data_len)40 int msg_send_msg(socket_t *to, uint16_t client_id, uint8_t type,
41                  char *data, int data_len)
42 {
43     char buf[MSG_MAX_LEN + sizeof(msg_hdr_t)];
44     int len; /* length for entire packet */
45     //uint16_t tmp_id;
46 
47     if(data_len > MSG_MAX_LEN)
48         return -1;
49 
50     switch(type)
51     {
52         case MSG_TYPE_HELLO:
53         case MSG_TYPE_HELLOACK:
54         case MSG_TYPE_DATA0:
55         case MSG_TYPE_DATA1:
56             memcpy(buf+sizeof(msg_hdr_t), data, data_len);
57             break;
58 
59         case MSG_TYPE_GOODBYE:
60         case MSG_TYPE_KEEPALIVE:
61         case MSG_TYPE_ACK0:
62         case MSG_TYPE_ACK1:
63             data_len = 0;
64             break;
65 
66         default:
67             return -1;
68     }
69 
70     len = data_len + sizeof(msg_hdr_t);
71     msg_init_header((msg_hdr_t *)buf, client_id, type, data_len);
72 
73     len = sock_send(to, buf, len);
74     if(len < 0)
75         return -1;
76     else if(len == 0)
77         return -2;
78     else
79         return 0;
80 }
81 
82 /*
83  * Sends a HELLO type message to the UDP tunnel with the specified host and
84  * port in the body.
85  * Returns 0 for success, -1 on error, or -2 to disconnect.
86  */
msg_send_hello(socket_t * to,char * host,char * port,uint16_t req_id)87 int msg_send_hello(socket_t *to, char *host, char *port, uint16_t req_id)
88 {
89     char *data;
90     int str_len;
91     int len;
92 
93     str_len = strlen(host) + strlen(port) + 2;
94     len = str_len + sizeof(req_id);
95 
96     data = malloc(len);
97     if(!data)
98         return -1;
99 
100     *((uint16_t *)data) = htons(req_id);
101 
102 #ifdef WIN32
103     _snprintf(data + sizeof(req_id), str_len, "%s %s", host, port);
104 #else
105     snprintf(data + sizeof(req_id), str_len, "%s %s", host, port);
106 #endif
107 
108     len = msg_send_msg(to, 0, MSG_TYPE_HELLO, data, len-1);
109     free(data);
110 
111     if(len < 0)
112         return -1;
113     else if(len == 0)
114         return -2;
115     else
116         return 0;
117 }
118 
119 /*
120  * Receives a message that is ready to be read from the UDP socket. Writes the
121  * body of the message into data, and sets the client ID, type, and length
122  * of the message.
123  * Returns 0 for success, -1 on error, or -2 to disconnect.
124  */
msg_recv_msg(socket_t * sock,socket_t * from,char * data,int data_len,uint16_t * client_id,uint8_t * type,uint16_t * length)125 int msg_recv_msg(socket_t *sock, socket_t *from, char *data, int data_len,
126                  uint16_t *client_id, uint8_t *type, uint16_t *length)
127 {
128     char buf[MSG_MAX_LEN + sizeof(msg_hdr_t)];
129     msg_hdr_t *hdr_ptr;
130     char *msg_ptr;
131     int ret;
132 
133     hdr_ptr = (msg_hdr_t *)buf;
134     msg_ptr = buf + sizeof(msg_hdr_t);
135 
136     ret = sock_recv(sock, from, buf, sizeof(buf));
137     if(ret < 0)
138         return -1;
139     else if(ret == 0)
140         return -2;
141 
142     *client_id = msg_get_client_id(hdr_ptr);
143     *type = msg_get_type(hdr_ptr);
144     *length = msg_get_length(hdr_ptr);
145 
146     if(ret-sizeof(msg_hdr_t) != *length)
147         return -1;
148 
149     *length = MIN(data_len, *length);
150     memcpy(data, msg_ptr, *length);
151 
152     return 0;
153 }
154