kategoria: ANSI C
[#1] [bsdsocket, sieci] Czy można ustawić timeout dla pakietu TCP?
hej,
zrobiłem prosty test sprawdzający czy komputer ma połączenie z siecią.
Problem jest taki, że jak odepnę kabel sieciowy to polecenie connect() czeka ze 20s zanim zakończy.

Jeżeli użyję opcji:
setsockopt(my_socket, IPPROTO_TCP, TCP_MAXRT, (char*)&timeout, sizeof(timeout));

gdzie TCP_MAXRT oznacza 5

To pod WinUAE na Windowsie działa, tj. np czeka max 1 sekunde na timeout.
TCP_MAXRT jest dostępne w socketach Windowsa, ale w normalnej bibliotece bsdsocket nie ma tej opcji
a nie mogłem znaleźć odpowiednika.

Probowałem też:
struct timeval timeout;      
timeout.tv_sec = 1;
timeout.tv_usec = 0; 
setsockopt(my_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof timeout);
setsockopt(my_socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof timeout);

ale też nie działa.

Poniżej cały kod, może macie jakiś pomysł - ja na studiach olałem sockety niestety xDD
#include <proto/exec.h>
#include <sys/socket.h>
#include <proto/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <stdio.h>

struct Library* SocketBase = NULL;

int main(void)
{
    // Try open socket library.
    SocketBase = (struct Library*)OpenLibrary("bsdsocket.library", 4);
	if (SocketBase == NULL) return 1;

	// try open a socket
	LONG my_socket = socket(AF_INET, SOCK_STREAM, 0);
	if (my_socket == -1 ) 
	{
		printf("error on socket creating\n");
	}
	else
	{
		printf("socket created\n");
	}

	int timeout = 1; 
	setsockopt(my_socket, IPPROTO_TCP, 5 , (char*)&timeout, sizeof(timeout));

	struct sockaddr_in addr;
	memset ( &addr , 0 , sizeof(struct sockaddr_in) );

	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr("216.58.213.0");
	addr.sin_port = htons(80);

	if (connect(my_socket, (struct sockaddr*)&addr, sizeof(addr)) != 0)
        printf("Failed");
    else
        printf("Success");

	CloseSocket(my_socket);
	CloseLibrary(SocketBase);

	return 0;
}
[wyróżniony] [#2] Re: [bsdsocket, sieci] Czy można ustawić timeout dla pakietu TCP?

@mateusz_s, post #1

Spróbuj użyć funkcji IoctlSocket() z parametrami FIONBIO i wskaźnikiem do wartości 1, by ustawić tryb nie-blokujący dla socketa.

Następnie wywołaj connect(), po czym użyj funkcji WaitSelect(), by sprawdzić stan socketa (czy poprawnie nawiązano połączenie i czy są dane do odczytu bądź zapisu) z wybranym Timeoutem.

Jako parametr dla WaitSelect() podaje się zbiór socketów. Możesz go utworzyć w następujący sposób:

fd_set set;

FD_ZERO(&set);
FD_SET(my_socket, &set);

Wynikowe zbiory (read, write, except) sprawdzasz za pomocą FD_ISSET(my_socket, &set).

Ostatnia aktualizacja: 25.04.2023 07:27:52 przez Hexmage960
1
[wyróżniony] [#3] Re: [bsdsocket, sieci] Czy można ustawić timeout dla pakietu TCP?

@mateusz_s, post #1

int timeout = 1; 
setsockopt(my_socket, IPPROTO_TCP, 5 , (char*)&timeout, sizeof(timeout));

Nie mieszaj api windowsow z api amigi - unikniesz wielu problemow.
TCP_MAXRT jest flaga do windowsowego stosu tcp i to od wersji Vista czy server 2003, nie istnieje w api amigowym. flaga o wartosci 5 w api AmiTCP nie istnieje, poniewaz na amidze opcje setsockopts sa bitami i w tym przypadku kod 5 bylby odpowiednikiem SO_DEBUG | SO_REUSEADDR. W dodatku te opcje stosuje sie do socketu a nie protokolu, czyli zamiast IPPPROTO_TCP powinno byc wtedy SOL_SOCKET
To, ze flaga TCP_MAXRT dziala w WinUAE to blad, ktory mozna by zglosic autorowi.
Ustawianie timeoutu na poziomie protokolu bedzie mialo wplyw na wszystkie inne polaczenia a przeciez celem tylko jest sprawdzenie czy jest polaczenie - wystarczy wiec ustawic to na poziomie socketu, ktory bedzie wykorzystany.
Ten kawalek kodu:
struct timeval timeout;      
timeout.tv_sec = 1;
timeout.tv_usec = 0; 
setsockopt(my_socket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof (timeout));
setsockopt(my_socket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof (timeout));

powinien dzialac.

A tak btw: wyciaganie kabla do testowania braku internetu w przypadku tcp srednio ma sens - kable to poziom hardware (layer 1) a tcp to layer 4 a z zalozenia sa one niezalezne od siebie. Tcp bedzie dalej wysylal dane do ip, ip do drivera sana a ten do hardware dopoki nie zostanie przekroczony czas oczekiwania na odpowiedz. Nawet wtedy nie ma jednak pewnosci czy w ogole nie ma polaczenia z internetem czy tylko moze z hostem, do ktorego sprawdzasz polaczenie - nie ma sensownego kodu bledu, po ktorym mozna by to wykryc.
Na tym polega tez fundamentlny problem w twoim rozwiazaniu - sprawdzasz tylko, czy mozesz sie polaczyc z jakims hostem a nie czy internet jest czy go nie ma. Co w sytuacji, gdy internet jest ale sprawdzany host akurat jest niedostepny?
Z poziomu tcp/ip nie ma dobrej metody na wykrywanie braku internetu - musialbys zejsc poziom nizej i sprawdzac czy interfejs jest podniesiony. W przypadku amigi mozna np. odwolac sie bezposrednio do device sieciowego.

Ostatnia aktualizacja: 25.04.2023 09:10:23 przez docent
2
[wyróżniony] [#4] Re: [bsdsocket, sieci] Czy można ustawić timeout dla pakietu TCP?

@docent, post #3

Część deviców SanaII ma także obsługę wykrywania wypięcia kabla, więc nie tylko prostymi timeoutami da się ogarnąć problem z połączeniem.
1
[#5] Re: [bsdsocket, sieci] Czy można ustawić timeout dla pakietu TCP?

@docent, post #3

Dzięki za podpowiedz, popróbuję..
[#6] Re: [bsdsocket, sieci] Czy można ustawić timeout dla pakietu TCP?

@michal_zukowski, post #4

??? No przeciez tak wlasnie napisalem, ze nie powinno sie uzywac do tego timeoutu tcp tylko z poziomu interfejsu lub przez sana device sprawdzac czy jest online...

Ostatnia aktualizacja: 25.04.2023 11:19:14 przez docent
[wyróżniony] [#7] Re: [bsdsocket, sieci] Czy można ustawić timeout dla pakietu TCP?

@mateusz_s, post #5

Zainteresuj sie SIOCGIFCONF i SIOCGIFFLAGS. Za pomoca ioctl SIOCGIFCONF pobierzesz liste interfejsow. nastepnie na kazdym interfejsie ioctl SIOCGIFFLAGS pobierze flagi interfejsu - pomin wszystkie interfejsy z flaga IFF_LOOPBACK, dla pozostalych jesli flagi & IFF_UP, to interfejs jest online.
1
[#8] Re: [bsdsocket, sieci] Czy można ustawić timeout dla pakietu TCP?

@docent, post #7

dzięki, posprawdzam.. OK
[#9] Re: [bsdsocket, sieci] Czy można ustawić timeout dla pakietu TCP?

@Hexmage960, post #2

@HexMage
Sprawdziłem na razie Twój pomysł,
niestety gdy mode = 1 (czyli non blocking) to funkcja connect() owszem już nie czeka -
ale zwraca błąd, natomaist funkcja WaitSelect() zwraca 0. Wiec nie można zebrać żadnych informacji.

Gdy tryb jest blockujący cztli mode = 0, to poniższy kod zwraca sensowne informacje gdy jestesmy online lub offline. Ale niestety oczekujemy na connet() znowu.

Poniższy kod:
// Try open socket library.
    SocketBase = (struct Library*)OpenLibrary("bsdsocket.library", 4);
	if (SocketBase == NULL) return 1;

	// try open a socket
	LONG my_socket = socket(AF_INET, SOCK_STREAM, 0);
	if (my_socket == -1 ) 
	{
		printf("error on socket creating\n");
	}
	else
	{
		printf("socket created\n");
	}

	printf("socket: %d", my_socket);

	// set socket to non-blocking mode
	LONG mode = 1;

	LONG result = IoctlSocket(my_socket, FIONBIO, &mode);
	if (result == -1)
  		printf("\nioctlsocket failed with error %d\n", result);


	struct sockaddr_in addr;
	memset ( &addr , 0 , sizeof(struct sockaddr_in) );

	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr("216.58.213.0");
	addr.sin_port = htons(80);

	if (connect(my_socket, (struct sockaddr*)&addr, sizeof(addr)) != 0)
        printf("\nFailed\n");
    else
        printf("\nSuccess\n");

   fd_set reading, writing, except;
   int rc, max_sock;
   
	struct timeval timeout;
	timeout.tv_sec = 5;
	timeout.tv_usec = 0;
 
   /* initialize the bit sets */
   FD_ZERO( &reading );
   FD_ZERO( &writing );
   FD_ZERO( &except );
 
   /* add r, w, and e to the appropriate bit set */
   FD_SET( my_socket, &reading );
   FD_SET( my_socket, &writing );
   FD_SET( my_socket, &except );
 
   /* for efficiency, what's the maximum socket number? */
   max_sock = 3;
 
   /* make select poll by sending a 0 timeval */
   memset( &timeout, 0, sizeof(timeout) );
 
   /* poll */
   rc = WaitSelect( max_sock, &reading, &writing, &except, &timeout, NULL );
 
   if ( rc < 0 ) {
        /* an error occurred during the select() */
        printf("ERROR");
   }
   else if ( rc == 0 ) {
        /* none of the sockets were ready in our little poll */
        printf( "nobody is home.\n" );
   } else {
        /* at least one of the sockets is ready */
        printf("r is %s\n", FD_ISSET(my_socket,&reading) ? "READY" : "NOT READY");
        printf("w is %s\n", FD_ISSET(my_socket,&writing) ? "READY" : "NOT READY");
        printf("e is %s\n", FD_ISSET(my_socket,&except)  ? "READY" : "NOT READY");
   }

	CloseSocket(my_socket);
	CloseLibrary(SocketBase);


Ostatnia aktualizacja: 25.04.2023 19:04:20 przez mateusz_s
[wyróżniony] [#10] Re: [bsdsocket, sieci] Czy można ustawić timeout dla pakietu TCP?

@mateusz_s, post #9

A dlaczego czyścisz strukturę timeout? Ta struktura powinna wskazywać ile czasu chcesz czekać na połączenie.

Doczytałem, że faktycznie może być to zero i wtedy WaitSelect() blokuje połączenie dopóki nie otrzyma odpowiedzi. Z drugiej jednak strony jeżeli ta funkcja zwraca 0 to minął timeout.

Spróbuj może z dodatnim czasem. Może to być np. pół sekundy. Ja jak używałem socketów to dawałem dodatni czas.

Przepraszam, skoro connect() zwraca błąd to inna sytuacja. Dzięki za przetestowanie pomysłu.

Ostatnia aktualizacja: 25.04.2023 20:06:26 przez Hexmage960
1
[#11] Re: [bsdsocket, sieci] Czy można ustawić timeout dla pakietu TCP?

@Hexmage960, post #10

@HexMAge

aaaaaaaaaaaaaaaaaaaajjj... ale ze mnie pała..
masz rację, nie zauważyłem tego zerowania, został jakiś śmieć,
działa bardzo dobrze teraz jak należy, jak niema kabla to czeka np. 1 sekunde i koniec.

wielkie dzięki OK

jeszcze spróbuje zrobić sposobem @docenta, to chyba by był bardziej uniwersalny bo nie trzeba by
wybierać sobie serwera.. ale póki co jest git.. taki sposób też wystarczy.
[#12] Re: [bsdsocket, sieci] Czy można ustawić timeout dla pakietu TCP?

@mateusz_s, post #11

Hej,
Ma Ktoś ochotę przetestować program na swoim interfejsie sieciowym?

W tym momencie program jest już postaci Commodity. Zapisuje też stan sieci
do zmiennej środowiskowen ENV:msInternetStatus (którą można wykorzystać np. na pasku WB do monitowania stanu)

Na ten moment do testów stan sieci jest wypisywany w konsoli co 2 sekundy.
Gdy wypinamy kabel, lub połączenie się przerywa to od razu widzimy komunikat ze jestsmeny odlaczeni,
po wepnięciu kabla znów jest komunikat ze jest OK..

W TOOLTYPES, możeny ustawić primary IP i secondary IP (jeśli pierwszy zawiedzie test)
i czas co ile test ma cię wykonywać - np. 8sekund.

Na razie testowanie na:
0. WinUAE --- OK
1. adapter eth na karcie V1200 + Roadshow -- OK
2. Amiga A2000, zz9000, Roadshow -- OK
3. karta ariadne + Miami -- OK
4. X-Surf 100 + AmiTCP -- Tu był ciekawy problem - po wyjęciu kabla nie można było otworzyć biblioteki Socket,
dałem dodatkowe sprawdzenie i powinno być ok

Jesli Ktoś chcialby przetestować to dajcie znać jaki macie ionterfejs sieciowy i stos TCP (Roadshow/Miami, AmTCP ..itp)
plik: http://mstanisz.website.pl/tmp/amiga/msInternetStatus-1.zip
(ponieważ to program commodity - można go zatrzymać/uruchomić za pomocą programu Exchange w sys:tools/commodity)




---

Ostatnia aktualizacja: 29.04.2023 00:25:31 przez mateusz_s
2
[#13] Re: [bsdsocket, sieci] Czy można ustawić timeout dla pakietu TCP?

@mateusz_s, post #12

Na MorphOSie dostał jakiegoś locka
wypisał:
>> JEST POLACZENIE <<>> JEST POLACZENIE <<>> JEST POLACZENIE <<>> JEST POLACZENIE <<
i tyle.
Program nie reaguja na Control C i inne sygnały (jak dla mnie to błąd). W debuglogu nic nie ma więc po pamięci nie jeździ
[#14] Re: [bsdsocket, sieci] Czy można ustawić timeout dla pakietu TCP?

@michal_zukowski, post #13

To wersja tylko do testu wypisuje co 2sec. stan sieci.
Jeśli odłączysz kabel powinno wypisywać BRAK.
Domyślnie tej konsoli nie będzie.
[#15] Re: [bsdsocket, sieci] Czy można ustawić timeout dla pakietu TCP?

@mateusz_s, post #14

Wypisał 4 razy tekst i przestał działać. Nie wyszedł z programu, nie zawiesił się, po prostu przestał wypisywać. Nie zdążyłem odpiąć kabla :P. Coś jest nie tak
[#16] Re: [bsdsocket, sieci] Czy można ustawić timeout dla pakietu TCP?

@michal_zukowski, post #15

Aha.. ciekawe xD dzięki za test a co to za stos tcp? Roadshow? Czy jakiś morphosowy. W sumie to robiłem to pod aos 3.x może pod mophosa cos tam trzeba inaczej.
Na stronie www.PPA.pl, podobnie jak na wielu innych stronach internetowych, wykorzystywane są tzw. cookies (ciasteczka). Służą ona m.in. do tego, aby zalogować się na swoje konto, czy brać udział w ankietach. Ze względu na nowe regulacje prawne jesteśmy zobowiązani do poinformowania Cię o tym w wyraźniejszy niż dotychczas sposób. Dalsze korzystanie z naszej strony bez zmiany ustawień przeglądarki internetowej będzie oznaczać, że zgadzasz się na ich wykorzystywanie.
OK, rozumiem