Nasiedziałem się nad pewnym problemem zdecydowanie dłużej niż siedzieć się nad nim powinno.
W pisanym systemie Callcenter podpinam się do FreeSWITCHa socketem TCP coby w tenże sposób kontrolować jego zachowanie. Jak się można domyślić – stan połączenia między serwerem a centralką telefoniczną jest dla aplikacji callcenter dość kluczowy. Okazało się jednak, że standardowa logika wykrywania błędów połączenia (tzn. po prostu łapanie wyjątków występujących podczas komunikacji i odpowiednia na to zdarzenie reakcja) to czasami zbyt mało… Niestety, da się osiągnąć stan, w którym aplikacja myśli, że FS działa pomimo tego, że jest wyłączony.
Problematyczna sytuacja występuje w ściśle określonych warunkach. Po pierwsze – callcenter musi nie mieć nic do roboty, w przeciwnym wypadku oczywiście da się wykryć utratę połączenia przez normalne wyjątki lecące podczas komunikacji z FS. Po drugie – FreeSWITCH musi być zamknięty "grzecznie", tzn ładną komendą "shutdown", a nie przez brutalne zamknięcie jego okna albo zwyczajne ubicie procesu. Gdy te dwie okoliczności są spełnione, to socket (mimo oczywistego braku partnera do zerojedynkowej konwersacji po drugiej stronie kabla) cały czas "myśli", że połączenie jest aktywne.
I na nic zdają się porady wyczytane na MSDN, jak wysyłanie pustych bajtów w non-blocking-mode. Czy metoda Poll, która niby powinna mi wykryć ów problem.
Na rozwiązanie naprowadził mnie wynik wywołania komendy netstat, która pokazała jasno, że takie połączenia, owszem, są widoczne, ale ich stan to "CLOSE_WAIT". Pozostało znaleźć sposób na wyłuskanie skądś tej informacji i periodyczne jej sprawdzanie. No właśnie… tylko skąd, skoro standardowe API socketa takich danych nie udostępnia?
W poszukiwaniach natknąłem się na ciekawą klasę, o której istnieniu nie miałem wcześniej pojęcia: IPGlobalProperties. Jej statyczna metoda GetActiveTcpConnections zwraca tablicę obiektów TcpConnectionInformation, które to z kolei mają właściwość enum State.
Dalej – już z górki.