1/* hey emacs! -*- Mode: C; c-file-style: "k&r"; indent-tabs-mode: nil -*- */ 2/* 3 * tftpd_mcast.c 4 * support routine for multicast server 5 * 6 * $Id: tftpd_mcast.c,v 1.6 2003/04/25 00:16:19 jp Exp $ 7 * 8 * Copyright (c) 2000 Jean-Pierre Lefebvre <helix@step.polymtl.ca> 9 * and Remi Lefebvre <remi@debian.org> 10 * 11 * atftp is free software; you can redistribute them and/or modify them 12 * under the terms of the GNU General Public License as published by the 13 * Free Software Foundation; either version 2 of the License, or (at your 14 * option) any later version. 15 * 16 */ 17 18#include "config.h" 19 20#include <stdio.h> 21#include <stdlib.h> 22#include <string.h> 23#include <sys/types.h> 24#include <sys/socket.h> 25#include <netinet/in.h> 26#include "tftpd.h" 27#include "tftp_def.h" 28#include "logger.h" 29 30#define START 0 31#define GET_ENUM 1 32#define GET_GRP 2 33#define EXPAND 3 34 35pthread_mutex_t mcast_tid_list = PTHREAD_MUTEX_INITIALIZER; 36 37int parse_ip(char *string, char **res_ip); 38int parse_port(char *string, char **res_port); 39 40struct tid { 41 char *addr; 42 short port; 43 int used; 44 struct tid *next; 45}; 46 47struct tid *tid_list = NULL; 48 49/* 50 * Return a free IP/Port for the multicast transfer 51 */ 52int tftpd_mcast_get_tid(char **addr, short *port) 53{ 54 struct tid *current = tid_list; 55 56 pthread_mutex_lock(&mcast_tid_list); 57 /* walk the list for a free tid */ 58 while (current != NULL) 59 { 60 if (current->used == 0) 61 { 62 *addr = current->addr; 63 *port = current->port; 64 current->used = 1; 65 pthread_mutex_unlock(&mcast_tid_list); 66 return OK; 67 } 68 else 69 current = current->next; 70 } 71 pthread_mutex_unlock(&mcast_tid_list); 72 return ERR; 73} 74 75int tftpd_mcast_free_tid(char *addr, short port) 76{ 77 struct tid *current = tid_list; 78 79 pthread_mutex_lock(&mcast_tid_list); 80 while (current != NULL) 81 { 82 if ((current->used == 1) && (current->port == port) && 83 (strcmp(current->addr, addr) == 0)) 84 { 85 current->used = 0; 86 pthread_mutex_unlock(&mcast_tid_list); 87 return OK; 88 } 89 else 90 current = current->next; 91 } 92 pthread_mutex_unlock(&mcast_tid_list); 93 return ERR; 94} 95 96/* valid address specification: 97 239.255.0.0-239.255.0.20 98 239.255.0.0-20 99 239.255.0.0,1,2,3,8,10 100*/ 101/* valid port specification 102 1758 103 1758-1780 104 1758,1760,4000 105*/ 106int tftpd_mcast_parse_opt(char *addr, char *ports) 107{ 108 char *ip; 109 char *port; 110 struct tid *current = NULL; 111 struct tid *tmp = NULL; 112 113 while (1) 114 { 115 if (parse_ip(addr, &ip) != OK) 116 return ERR; 117 if (ip == NULL) 118 return OK; 119 while (1) 120 { 121 if (parse_port(ports, &port) != OK) 122 return ERR; 123 if (port == NULL) 124 break; 125 /* add this ip/port to the tid list */ 126 tmp = malloc(sizeof(struct tid)); 127 tmp->addr = strdup(ip); 128 tmp->port = (short)atoi(port); 129 tmp->used = 0; 130 tmp->next = NULL; 131 if (tid_list == NULL) 132 { 133 tid_list = tmp; 134 current = tid_list; 135 } 136 else 137 { 138 current->next = tmp; 139 current = tmp; 140 } 141 } 142 } 143} 144 145void tftpd_mcast_clean(void) 146{ 147 148 149} 150 151int parse_ip(char *string, char **res_ip) 152{ 153 static int state = START; 154 155 static char s[MAXLEN]; 156 static char *saveptr; 157 static char s2[MAXLEN]; 158 static char *saveptr2; 159 160 static int ip[4]; 161 static int tmp_ip[4]; 162 163 static int i; 164 165 int res; 166 char *tmp = NULL, *tmp2 = NULL; 167 static char out[MAXLEN]; 168 169 *res_ip = NULL; 170 171 while (1) 172 { 173 switch (state) 174 { 175 case START: 176 Strncpy(s, string, MAXLEN); 177 tmp = strtok_r(s, ",", &saveptr); 178 if (tmp == NULL) 179 { 180 state = START; 181 return ERR; 182 } 183 else 184 state = GET_GRP; 185 break; 186 case GET_ENUM: 187 tmp = strtok_r(NULL, ",", &saveptr); 188 if (tmp == NULL) 189 { 190 state = START; 191 return OK; 192 } 193 else 194 state = GET_GRP; 195 break; 196 case GET_GRP: 197 Strncpy(s2, tmp, MAXLEN); 198 tmp = strtok_r(s2, "-", &saveptr2); 199 if (tmp == NULL) 200 { 201 state = START; 202 return ERR; 203 } 204 res = sscanf(tmp, "%d.%d.%d.%d", &tmp_ip[0], &tmp_ip[1], 205 &tmp_ip[2], &tmp_ip[3]); 206 if (res == 4) 207 { 208 for (i=0; i < 4; i++) 209 ip[i] = tmp_ip[i]; 210 } 211 else 212 { 213 if (res == 1) 214 { 215 ip[3] = tmp_ip[0]; 216 } 217 else 218 { 219 state = START; 220 return ERR; 221 } 222 } 223 tmp2 = strtok_r(NULL, "-", &saveptr2); 224 if (tmp2 == NULL) 225 { 226 state = GET_ENUM; 227 snprintf(out, sizeof(out), "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); 228 *res_ip = out; 229 return OK; 230 } 231 else 232 { 233 sscanf(tmp2, "%d", &tmp_ip[0]); 234 i = ip[3]; 235 if (i >= tmp_ip[0]) 236 { 237 logger(LOG_ERR, "Bad address range: %d.%d.%d.%d-%d", 238 ip[0], ip[1], ip[2], ip[3], tmp_ip[0]); 239 return ERR; 240 } 241 state = EXPAND; 242 } 243 break; 244 case EXPAND: 245 if (i > tmp_ip[0]) 246 { 247 state = GET_ENUM; 248 break; 249 } 250 snprintf(out, sizeof(out), "%d.%d.%d.%d", ip[0], ip[1], ip[2], i); 251 i++; 252 *res_ip = out; 253 return OK; 254 break; 255 } 256 } 257} 258 259int parse_port(char *string, char **res_port) 260{ 261 static int state = START; 262 263 static char s[MAXLEN]; 264 static char *saveptr; 265 static char s2[MAXLEN]; 266 static char *saveptr2; 267 268 static int port; 269 static int tmp_port; 270 271 static int i; 272 273 int res; 274 char *tmp = NULL, *tmp2 = NULL; 275 static char out[MAXLEN]; 276 277 *res_port = NULL; 278 279 while (1) 280 { 281 switch (state) 282 { 283 case START: 284 Strncpy(s, string, MAXLEN); 285 tmp = strtok_r(s, ",", &saveptr); 286 if (tmp == NULL) 287 { 288 state = START; 289 return ERR; 290 } 291 else 292 state = GET_GRP; 293 break; 294 case GET_ENUM: 295 tmp = strtok_r(NULL, ",", &saveptr); 296 if (tmp == NULL) 297 { 298 state = START; 299 return OK; 300 } 301 else 302 state = GET_GRP; 303 break; 304 case GET_GRP: 305 Strncpy(s2, tmp, MAXLEN); 306 tmp = strtok_r(s2, "-", &saveptr2); 307 if (tmp == NULL) 308 { 309 state = START; 310 return ERR; 311 } 312 res = sscanf(tmp, "%d", &port); 313 if (res != 1) 314 { 315 state = START; 316 return ERR; 317 } 318 tmp2 = strtok_r(NULL, "-", &saveptr2); 319 if (tmp2 == NULL) 320 { 321 state = GET_ENUM; 322 snprintf(out, sizeof(out), "%d", port); 323 *res_port = out; 324 return OK; 325 } 326 else 327 { 328 sscanf(tmp2, "%d", &tmp_port); 329 i = port; 330 if (i >= tmp_port) 331 { 332 logger(LOG_ERR, "Bad port range: %d-%d", i, tmp_port); 333 return ERR; 334 } 335 state = EXPAND; 336 } 337 break; 338 case EXPAND: 339 if (i > tmp_port) 340 { 341 state = GET_ENUM; 342 break; 343 } 344 snprintf(out, sizeof(out), "%d", i); 345 i++; 346 *res_port = out; 347 return OK; 348 break; 349 } 350 } 351} 352