[svn-upgrade] new version iodine (0.6.0~rc1)
[debian/iodine.git] / src / user.c
1 /*
2  * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <stdio.h>
18 #include <stdint.h>
19 #include <time.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <signal.h>
23 #include <unistd.h>
24 #include <fcntl.h>
25
26 #ifdef WINDOWS32
27 #include <winsock2.h>
28 #else
29 #include <netdb.h>
30 #endif
31
32 #include "common.h"
33 #include "encoding.h"
34 #include "user.h"
35
36 struct user users[USERS];
37
38 int
39 init_users(in_addr_t my_ip, int netbits)
40 {
41         int i;
42         int skip = 0;
43         char newip[16];
44         int created_users = 0;
45
46         int maxusers;
47
48         in_addr_t netmask = 0;
49         struct in_addr net;
50         struct in_addr ipstart;
51
52         for (i = 0; i < netbits; i++) {
53                 netmask = (netmask << 1) | 1;
54         }
55         netmask <<= (32 - netbits);
56         net.s_addr = htonl(netmask);
57         ipstart.s_addr = my_ip & net.s_addr;
58
59         maxusers = (1 << (32-netbits)) - 3; /* 3: Net addr, broadcast addr, iodined addr */
60         
61         memset(users, 0, USERS * sizeof(struct user));
62         for (i = 0; i < USERS; i++) {
63                 in_addr_t ip;
64                 users[i].id = i;
65                 snprintf(newip, sizeof(newip), "0.0.0.%d", i + skip + 1);
66                 ip = ipstart.s_addr + inet_addr(newip);
67                 if (ip == my_ip && skip == 0) {
68                         /* This IP was taken by iodined */
69                         skip++;
70                         snprintf(newip, sizeof(newip), "0.0.0.%d", i + skip + 1);
71                         ip = ipstart.s_addr + inet_addr(newip);
72                 }
73                 users[i].tun_ip = ip;
74                 net.s_addr = ip;
75                 if (maxusers--  < 1) {
76                         users[i].disabled = 1;
77                 } else {
78                         users[i].disabled = 0;
79                         created_users++;
80                 }
81                 users[i].active = 0;
82                 /* Rest is reset on login ('V' packet) */
83         }
84
85         return created_users;
86 }
87
88 const char*
89 users_get_first_ip()
90 {
91         struct in_addr ip;
92         ip.s_addr = users[0].tun_ip;
93         return inet_ntoa(ip);
94 }
95
96 int
97 users_waiting_on_reply()
98 {
99         int ret;
100         int i;
101
102         ret = 0;
103         for (i = 0; i < USERS; i++) {
104                 if (users[i].active && !users[i].disabled && 
105                         users[i].last_pkt + 60 > time(NULL) &&
106                         users[i].q.id != 0 && users[i].conn == CONN_DNS_NULL) {
107                         ret++;
108                 }
109         }
110         
111         return ret;
112 }
113
114 int
115 find_user_by_ip(uint32_t ip)
116 {
117         int ret;
118         int i;
119
120         ret = -1;
121         for (i = 0; i < USERS; i++) {
122                 if (users[i].active && !users[i].disabled &&
123                         users[i].last_pkt + 60 > time(NULL) &&
124                         ip == users[i].tun_ip) {
125                         ret = i;
126                         break;
127                 }
128         }
129         return ret;
130 }
131
132 int
133 all_users_waiting_to_send()
134 /* If this returns true, then reading from tun device is blocked.
135    So only return true when all clients have at least one packet in
136    the outpacket-queue, so that sending back-to-back is possible
137    without going through another select loop.
138 */
139 {
140         time_t now;
141         int ret;
142         int i;
143
144         ret = 1;
145         now = time(NULL);
146         for (i = 0; i < USERS; i++) {
147                 if (users[i].active && !users[i].disabled &&
148                         users[i].last_pkt + 60 > now &&
149                         ((users[i].conn == CONN_RAW_UDP) || 
150                         ((users[i].conn == CONN_DNS_NULL) 
151 #ifdef OUTPACKETQ_LEN
152                                 && users[i].outpacketq_filled < 1
153 #else
154                                 && users[i].outpacket.len == 0
155 #endif
156                         ))) {
157
158                         ret = 0;
159                         break;
160                 }
161         }
162         return ret;
163 }
164
165 int
166 find_available_user()
167 {
168         int ret = -1;
169         int i;
170         for (i = 0; i < USERS; i++) {
171                 /* Not used at all or not used in one minute */
172                 if ((!users[i].active || users[i].last_pkt + 60 < time(NULL)) && !users[i].disabled) {
173                         users[i].active = 1;
174                         users[i].last_pkt = time(NULL);
175                         users[i].fragsize = 4096;
176                         users[i].conn = CONN_DNS_NULL;
177                         ret = i;
178                         break;
179                 }
180         }
181         return ret;
182 }
183
184 void
185 user_switch_codec(int userid, struct encoder *enc)
186 {
187         if (userid < 0 || userid >= USERS)
188                 return;
189         
190         users[userid].encoder = enc;
191 }
192
193 void
194 user_set_conn_type(int userid, enum connection c)
195 {
196         if (userid < 0 || userid >= USERS)
197                 return;
198
199         if (c < 0 || c >= CONN_MAX)
200                 return;
201         
202         users[userid].conn = c;
203 }
204