diff options
Diffstat (limited to 'toxcore/network.c')
-rw-r--r-- | toxcore/network.c | 218 |
1 files changed, 218 insertions, 0 deletions
diff --git a/toxcore/network.c b/toxcore/network.c new file mode 100644 index 00000000..2bcf7d61 --- /dev/null +++ b/toxcore/network.c | |||
@@ -0,0 +1,218 @@ | |||
1 | /* network.h | ||
2 | * | ||
3 | * Functions for the core networking. | ||
4 | * | ||
5 | * Copyright (C) 2013 Tox project All Rights Reserved. | ||
6 | * | ||
7 | * This file is part of Tox. | ||
8 | * | ||
9 | * Tox is free software: you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation, either version 3 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * Tox is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with Tox. If not, see <http://www.gnu.org/licenses/>. | ||
21 | * | ||
22 | */ | ||
23 | |||
24 | #include "network.h" | ||
25 | |||
26 | /* returns current UNIX time in microseconds (us). */ | ||
27 | uint64_t current_time(void) | ||
28 | { | ||
29 | uint64_t time; | ||
30 | #ifdef WIN32 | ||
31 | /* This probably works fine */ | ||
32 | FILETIME ft; | ||
33 | GetSystemTimeAsFileTime(&ft); | ||
34 | time = ft.dwHighDateTime; | ||
35 | time <<= 32; | ||
36 | time |= ft.dwLowDateTime; | ||
37 | time -= 116444736000000000UL; | ||
38 | return time / 10; | ||
39 | #else | ||
40 | struct timeval a; | ||
41 | gettimeofday(&a, NULL); | ||
42 | time = 1000000UL * a.tv_sec + a.tv_usec; | ||
43 | return time; | ||
44 | #endif | ||
45 | } | ||
46 | |||
47 | /* return a random number | ||
48 | NOTE: this function should probably not be used where cryptographic randomness is absolutely necessary */ | ||
49 | uint32_t random_int(void) | ||
50 | { | ||
51 | #ifndef VANILLA_NACL | ||
52 | //NOTE: this function comes from libsodium | ||
53 | return randombytes_random(); | ||
54 | #else | ||
55 | return random(); | ||
56 | #endif | ||
57 | } | ||
58 | |||
59 | /* Basic network functions: | ||
60 | Function to send packet(data) of length length to ip_port */ | ||
61 | int sendpacket(int sock, IP_Port ip_port, uint8_t *data, uint32_t length) | ||
62 | { | ||
63 | ADDR addr = {AF_INET, ip_port.port, ip_port.ip}; | ||
64 | return sendto(sock, (char *) data, length, 0, (struct sockaddr *)&addr, sizeof(addr)); | ||
65 | } | ||
66 | |||
67 | /* Function to receive data, ip and port of sender is put into ip_port | ||
68 | the packet data into data | ||
69 | the packet length into length. | ||
70 | dump all empty packets. */ | ||
71 | static int receivepacket(int sock, IP_Port *ip_port, uint8_t *data, uint32_t *length) | ||
72 | { | ||
73 | ADDR addr; | ||
74 | #ifdef WIN32 | ||
75 | int addrlen = sizeof(addr); | ||
76 | #else | ||
77 | uint32_t addrlen = sizeof(addr); | ||
78 | #endif | ||
79 | (*(int32_t *)length) = recvfrom(sock, (char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen); | ||
80 | |||
81 | if (*(int32_t *)length <= 0) | ||
82 | return -1; /* nothing received or empty packet */ | ||
83 | |||
84 | ip_port->ip = addr.ip; | ||
85 | ip_port->port = addr.port; | ||
86 | return 0; | ||
87 | } | ||
88 | |||
89 | void networking_registerhandler(Networking_Core *net, uint8_t byte, packet_handler_callback cb, void *object) | ||
90 | { | ||
91 | net->packethandlers[byte].function = cb; | ||
92 | net->packethandlers[byte].object = object; | ||
93 | } | ||
94 | |||
95 | void networking_poll(Networking_Core *net) | ||
96 | { | ||
97 | IP_Port ip_port; | ||
98 | uint8_t data[MAX_UDP_PACKET_SIZE]; | ||
99 | uint32_t length; | ||
100 | |||
101 | while (receivepacket(net->sock, &ip_port, data, &length) != -1) { | ||
102 | if (length < 1) continue; | ||
103 | |||
104 | if (!(net->packethandlers[data[0]].function)) continue; | ||
105 | |||
106 | net->packethandlers[data[0]].function(net->packethandlers[data[0]].object, ip_port, data, length); | ||
107 | } | ||
108 | } | ||
109 | |||
110 | uint8_t at_startup_ran; | ||
111 | static int at_startup(void) | ||
112 | { | ||
113 | if (at_startup_ran != 0) | ||
114 | return 0; | ||
115 | |||
116 | #ifdef WIN32 | ||
117 | WSADATA wsaData; | ||
118 | |||
119 | if (WSAStartup(MAKEWORD(2, 2), &wsaData) != NO_ERROR) | ||
120 | return -1; | ||
121 | |||
122 | #else | ||
123 | srandom((uint32_t)current_time()); | ||
124 | #endif | ||
125 | srand((uint32_t)current_time()); | ||
126 | at_startup_ran = 1; | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | /* TODO: put this somewhere | ||
131 | static void at_shutdown(void) | ||
132 | { | ||
133 | #ifdef WIN32 | ||
134 | WSACleanup(); | ||
135 | #endif | ||
136 | } | ||
137 | */ | ||
138 | |||
139 | /* initialize networking | ||
140 | bind to ip and port | ||
141 | ip must be in network order EX: 127.0.0.1 = (7F000001) | ||
142 | port is in host byte order (this means don't worry about it) | ||
143 | returns Networking_Core object if no problems | ||
144 | returns NULL if there are problems */ | ||
145 | Networking_Core *new_networking(IP ip, uint16_t port) | ||
146 | { | ||
147 | if (at_startup() != 0) | ||
148 | return NULL; | ||
149 | |||
150 | /* initialize our socket */ | ||
151 | Networking_Core *temp = calloc(1, sizeof(Networking_Core)); | ||
152 | |||
153 | if (temp == NULL) | ||
154 | return NULL; | ||
155 | |||
156 | temp->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); | ||
157 | |||
158 | /* Check for socket error */ | ||
159 | #ifdef WIN32 | ||
160 | |||
161 | if (temp->sock == INVALID_SOCKET) { /* MSDN recommends this */ | ||
162 | free(temp); | ||
163 | return NULL; | ||
164 | } | ||
165 | |||
166 | #else | ||
167 | |||
168 | if (temp->sock < 0) { | ||
169 | free(temp); | ||
170 | return NULL; | ||
171 | } | ||
172 | |||
173 | #endif | ||
174 | |||
175 | /* Functions to increase the size of the send and receive UDP buffers | ||
176 | NOTE: uncomment if necessary */ | ||
177 | /* | ||
178 | int n = 1024 * 1024 * 2; | ||
179 | if(setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (char*)&n, sizeof(n)) == -1) | ||
180 | { | ||
181 | return -1; | ||
182 | } | ||
183 | |||
184 | if(setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (char*)&n, sizeof(n)) == -1) | ||
185 | return -1; | ||
186 | */ | ||
187 | |||
188 | /* Enable broadcast on socket */ | ||
189 | int broadcast = 1; | ||
190 | setsockopt(temp->sock, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof(broadcast)); | ||
191 | |||
192 | /* Set socket nonblocking */ | ||
193 | #ifdef WIN32 | ||
194 | /* I think this works for windows */ | ||
195 | u_long mode = 1; | ||
196 | /* ioctl(sock, FIONBIO, &mode); */ | ||
197 | ioctlsocket(temp->sock, FIONBIO, &mode); | ||
198 | #else | ||
199 | fcntl(temp->sock, F_SETFL, O_NONBLOCK, 1); | ||
200 | #endif | ||
201 | |||
202 | /* Bind our socket to port PORT and address 0.0.0.0 */ | ||
203 | ADDR addr = {AF_INET, htons(port), ip}; | ||
204 | bind(temp->sock, (struct sockaddr *)&addr, sizeof(addr)); | ||
205 | return temp; | ||
206 | } | ||
207 | |||
208 | /* function to cleanup networking stuff */ | ||
209 | void kill_networking(Networking_Core *net) | ||
210 | { | ||
211 | #ifdef WIN32 | ||
212 | closesocket(net->sock); | ||
213 | #else | ||
214 | close(net->sock); | ||
215 | #endif | ||
216 | free(net); | ||
217 | return; | ||
218 | } | ||