Проверка IP адреса переданного в String

vac
Offline
Зарегистрирован: 01.04.2017

День добрый гуру!

У меня наблюдаются сложности переходя с VB на С+ и производные от него.

Буду очень благодарен в небольшой помощи...

В скетче имеется настройка сетевых реквизитов для Ehternet шилда через serial интерфейс...

в функции проверка верности введенных данных:

bool checkIP (String ChStr)
{
  int a[4];
  bool result;
  char byff[16];
  int lenbyff;
result = true;
ChStr.toCharArray(buff[], lenbuff)

sscanf(buff[],"%d.%d.%d.%d",&a[0],&a[1],&a[2],&a[3]);
  for (int i=0; i <= 3; i++){
  if (a[i] < 0 && a[i] > 255) {
    result = false;
  }
  } 
   return checkIP;
}

'buff' was not declared in this scope



что не так то?

Yarik.Yar
Offline
Зарегистрирован: 07.09.2014

Объявили

char byff[16];

А используете

buff[]

:)

vac
Offline
Зарегистрирован: 01.04.2017

Пардон, но обявляю я имя массива и его размер, а использую массив целеком а не значение в индексе [16]?

Вот если кто поправит, буду благодаерн =)

Yarik.Yar
Offline
Зарегистрирован: 07.09.2014

Охх...ну, если не видите разницы в bUff и bYff, то совсем все плохо...

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Вы уж определитесь, byff или buff.

vac
Offline
Зарегистрирован: 01.04.2017

Спасибо =) - глаза замылились...

но конструкция к сожелению все равно не работает. при передаче любой строки в функцию результат работы

sscanf - 485, 0, 1000, 0

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

1. Уберите [] в строка 8 и 10. Вы знаете для чего это? Ну, а не знаете, чего пихать?

2. Перед строкой 10 поставьте вывод в Serial buff

3. После строки 10 поставьте вывод в Serial массива a

Посмотрите, что печатается и разберётесь.

 

vac
Offline
Зарегистрирован: 01.04.2017

Всем спасибо, работает так:

bool checkIP (String ChStr)
{
  int a[4];
  bool result;
  result = true;
  const char *str2 = ChStr.c_str();
    sscanf(str2,"%d.%d.%d.%d",&a[0],&a[1],&a[2],&a[3]);
  for (int i=0; i < 4; i++){
    if (a[i] < 0 || a[i] > 255) {result = false;}
  }  
   return result;
}

Я С+ только начинаю... после VB шаблоны сломаны =)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

vac,

оно, конечно, оптимизатор скорее всего всё разрулит и сам заменит, но некоторые люди считают не очень кошерным полагаться на оптимизатор, а предпочиатают писать нормально сами.

Так вот, запись 

   sscanf(str2,"%d.%d.%d.%d",&a[0],&a[1],&a[2],&a[3]); 

лоховская паскалевская. На С кошерно тоже самое писать вот так:

   sscanf(str2,"%d.%d.%d.%d", a , a+1, a+2, a+3);

 

mcmega
Offline
Зарегистрирован: 12.02.2014

Недоработана функция...

Если ввести например 192.168.0.1.1 валидацию проходит

или 192.168.0.0568 => 192.168.0.056 тоже проходит

правда я немного ее изменил

bool checkIP (String ip) {
  int a[4];
  const char *str = ip.c_str();
  sscanf(str, "%d.%d.%d.%d", a+0, a+1, a+2, a+3);
  Serial.println(str);
  for (int i = 0; i < 4; i++) {
    if (a[i] < 0 || a[i] > 255)
      return false;
  }
  return true;
}

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, а String то по значению нафига передавать? Он же будет память запрашивать и копироваться.

mcmega
Offline
Зарегистрирован: 12.02.2014

Так я делал как у автора... непонятный косяк ввожу 192.168.0.1.1 валидацию проходит...

как так, точка это же не цифра? и если 0123, то тоже проходит, просто обрезает при сохранении дальше у меня до 012

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, это Ваши дела. А String по значению передавать не надо.

mcmega
Offline
Зарегистрирован: 12.02.2014

Если сделать так

if (checkIP(root["setAP"][4])) {
//...
}

bool checkIP (String *ip) {
  int a[4];
  const char *str = ip.c_str();
  sscanf(str, "%d.%d.%d.%d", a+0, a+1, a+2, a+3);
  Serial.println(str);
  for (int i = 0; i < 4; i++) {
    if (a[i] < 0 || a[i] > 255)
      return false;
  }
  return true;
}
то ругается call of overloaded 'checkIP(ArduinoJson::JsonArraySubscript)' is ambiguous
Меня больше волнует почему если я передаю 192.168.108.0.1.2.234, то и в Serial получаю тоже, выходит sscanf неверно используется
ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Блин, Вы как в том анекдоте: или крестик сними, или трусы надень или в строке 7 пишите "->" вместо "." или в строке 5 пишите "&" вместо "*" (второе мне нравится больше).

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

mcmega пишет:

Меня больше волнует почему если я передаю 192.168.108.0.1.2.234, то и в Serial получаю тоже, выходит sscanf неверно используется

Я не вижу где Вы это получаете. Единственная печать в Вашем кусочке печатает введённую строку как есть, потому странно было бы. если бы она печатала не то, что ввелось. scanf тут при каких делах я не понимаю.

mcmega
Offline
Зарегистрирован: 12.02.2014

ЕвгенийП пишет:

Блин, Вы как в том анекдоте: или крестик сними, или трусы надень или в строке 7 пишите "->" вместо "." или в строке 5 пишите "&" вместо "*" (второе мне нравится больше).

Пробовал, не работает? Ошибка collect2.exe: error: ld returned 1 exit status если & использовать

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Туак не бывает, показывайте скетч полностью.

mcmega
Offline
Зарегистрирован: 12.02.2014

Он очень большой, сейчас соберу зависимые части

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Не надо

Вы же говорите, что проблема с sscanf

Ну и сделайте маленький пример, который демонстрирует проблему.

очень большой я смотреть не буду.

mcmega
Offline
Зарегистрирован: 12.02.2014

Пример


bool checkIP (String ip) {
  int a[4];
  bool result;
  result = true;
  const char *str = ip.c_str();
  sscanf(str, "%d.%d.%d.%d", a+0, a+1, a+2, a+3);
  Serial.println(str);
  for (int i = 0; i < 4; i++) {
    if (a[i] < 0 || a[i] > 255) {
      result = false;
    }
    Serial.print(a[i]);
  }
  Serial.println();
  return result;
}

Вход-выход: 192.168.0.01234 - 1921681081234, 192.168.108.512 - 192168108512

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Вы не поняли. Я прошу Вас дать скетч целиком, как есть.

То, что Вы дали - это плод Вашей фантазии. Вот Вы пишете

mcmega пишет:

Вход-выход: 192.168.0.01234 - 1921681081234, 192.168.108.512 - 192168108512

Но ведь это неправда! В какой строке Вашего скетча печатается дефис? А запятая в какой?

Дайте короткий скетч целиком, вместо с setup и loop, так, чтобы, если надо, я мог сам его запустить. Напишите, что Вы вводите, а СКОПИПАСТИТЕ его вывод.

mcmega
Offline
Зарегистрирован: 12.02.2014

Это я для наглядности написал

Я ж говорю, счетч очень большой я по websocket получаю данные вида {key:[ip,ip...]}.

Потом я его парсю и получаю чистый массив [192.168.108.0256, 192.168.108.1000, ...].

Передаю каждый элемент в функцию и это чистый вывод из функции с помощью Serial.print:

 

192.168.108.0256␍␊

192168108256␍␊

192.168.108.1000␍␊

1921681081000␍␊

mcmega
Offline
Зарегистрирован: 12.02.2014

Кажись я не там вывод Serial сделал, сори, все нормально

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Давненько булки не разминал - вот, набросал корявенький валидатор, навскидку разную дичь не пропускает:

bool checkIP(const char* ip) 
{
	int dotsCount = 0;
	bool bFirst = true;
	bool bLastCharIsDot = false;
	int lastPart = 0;
	
	while(*ip)
	{
		char ch = *ip++;
		
		if(ch == '.')
		{
			if(bFirst || bLastCharIsDot) // first char is '.' or last char is '.' (for example, .123.12 or 123..12)
				return false;
			
			
			bLastCharIsDot = true;
			dotsCount++;
			
			if(lastPart > 255) // malformed, for example, 999.23
				return false;
			
			lastPart = 0;
		}
		else
		if(ch >= '0' && ch <= '9')
		{
			int digit = ch - '0';
				
			lastPart *= 10;
			lastPart += digit;
			
			bLastCharIsDot = false;
		}
		else
			return false; // malformed
		
		
		bFirst = false;
	}
	
	return (lastPart < 256 && dotsCount == 3);
}

Пробовал здесь: https://www.jdoodle.com/online-compiler-c++ с вот такой программой:

#include <iostream>

using namespace std;

bool checkIP(const char* ip) 
{
	int dotsCount = 0;
	bool bFirst = true;
	bool bLastCharIsDot = false;
	int lastPart = 0;
	
	while(*ip)
	{
		char ch = *ip++;
		
		if(ch == '.')
		{
			if(bFirst || bLastCharIsDot) // first char is '.' or last char is '.' (for example, .123.12 or 123..12)
				return false;
			
			
			bLastCharIsDot = true;
			dotsCount++;
			
			if(lastPart > 255) // malformed, for example, 999.23
				return false;
			
			lastPart = 0;
		}
		else
		if(ch >= '0' && ch <= '9')
		{
			int digit = ch - '0';
				
			lastPart *= 10;
			lastPart += digit;
			
			bLastCharIsDot = false;
		}
		else
			return false; // malformed
		
		
		bFirst = false;
	}
	
	return (lastPart < 256 && dotsCount == 3);
}

int main() {

	cout<< checkIP("192.168.0.1.1") << endl;
	cout<< checkIP("192.168.1.1") << endl;
	cout<< checkIP("192.168.999.1") << endl;
	cout<< checkIP(".192.168.999.1") << endl;
	cout<< checkIP("192..168.999.1") << endl;
}

 

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Конечно, это не полноценный валидатор IP, если что, т.к. не учитывает, как минимум, диапазоны, и, как максимум - работает только с одним представлением адреса IPv4, а их - несколько.