Funkcje biblioteki zostały przygotowane w taki sposób, by móc z nich korzystać zarówno w trybie synchronicznym (działanie programu jest blokowane do zakończeniu operacji), jak i asynchroniczym (operacja jest rozpoczynana, a do czasu jej zakończenia program może robić inne rzeczy). Wyjątkiem są połączenia bezpośrednie, które pozwalają jedynie na połączenia asynchroniczne.
W trybie synchronicznym, po udanym zakończeniu funkcji gg_login()
, należy w pętli wywoływać funkcję gg_watch_fd()
, która po odebraniu informacji od serwera zwróci informację o zdarzeniu w strukturze gg_event
lub NULL
w przypadku błędu. Lista zdarzeń znajduje się poniżej.
Tryb asynchroniczny wymaga od programu obserwowania zmian na określonych deskryptorach za pomocą funkcji systemowych select()
czy poll()
, lub za pomocą mechanizmów pętli zdarzeń wbudowanych w wykorzystaną bibliotekę interfejsu użytkownika. Interesujące z punktu widzeniu połączenia asynchronicznego pola to fd
określające obserwowany deskryptor, pole check
będące maską bitową typu gg_check_t
, mówiącą czy obserwowana ma być możliwość odczytu i/lub zapisu oraz timeout
określające maksymalny czas wykonywania operacji. Gdy zaobserwuje się zmianę na deskryptorze należy wywołać funkcję gg_watch_fd()
i postępować podobnie jak w trybie synchronicznym.
timeout
, należy sprawdzić wartość flagi soft_timeout
. Jeśli jest równa 0
(tj. FALSE
), można przerwać połączenie i zwolnić zasoby, a jeśli jest różna (tj. TRUE
), należy wywołać gg_watch_fd()
ustawiając wcześniej timeout
na 0
, by dać szansę bibliotece zareagować na przekroczenie czasu operacji. Za pomocą mechanizmu soft_timeout
są realizowane próby połączenia z innymi portami, np. gdy domyślny port 8074 jest zablokowany oraz zwrotne połączenia bezpośrednie (7.x), gdy jedna ze stron połączenia znajduje się za routerem NAT lub firewallem.state
przyjmuje wartość GG_STATE_IDLE
. Przed dodaniem deskryptora fd
do listy obserwowanych, warto w ten sposób sprawdzić, czy dane połączenie nie jest już nieaktywne.SIGPIPE
, który domyślnie powoduje unicestwienie procesu. Dlatego, aby pozwolić bibliotece zareagować na zerwanie połączenia w sensowny sposób, należy ignorować sygnał w aplikacji.struct gg_session *sesja; struct gg_login_params parametry; struct gg_event *zdarzenie; memset(¶metry, 0, sizeof(parametry)); parametry.uin = 12345; parametry.password = "hasło"; sesja = gg_login(¶metry); if (!sesja) { błąd("Nie można się połączyć"); exit(1); } informacja("Połączono"); gg_send_message(sesja, 23456, "Cześć!"); while ((zdarzenie = gg_watch_fd(sesja))) { switch (zdarzenie->type) { // ... } gg_event_free(zdarzenie); } gg_logoff(sesja); gg_free_session(sesja);
gg_ping()
.struct gg_session *sesja; struct gg_login_params parametry; struct timeval tv; fd_set rd, wd; int wynik; memset(¶metry, 0, sizeof(parametry)); parametry.uin = 12345; parametry.password = "hasło"; parametry.async = 1; sesja = gg_login(¶metry); if (!sesja) { błąd("Nie można się połączyć"); exit(1); } for (;;) { FD_ZERO(&rd); FD_ZERO(&wd); if ((sesja->check & GG_CHECK_READ)) FD_SET(sesja->fd, &rd); if ((sesja->check & GG_CHECK_WRITE)) FD_SET(sesja->fd, &wd); if (sesja->timeout) { tv.tv_sec = sesja->timeout; tv.tv_usec = 0; } wynik = select(sesja->fd + 1, &rd, &wd, NULL, (sesja->timeout) ? &tv : NULL); if (!wynik) { błąd("Przekroczono czas operacji"); gg_free_session(sesja); exit(1); } if (wynik == -1) { if (errno != EINTR) { błąd("Błąd funkcji select()"); gg_free_session(sesja); exit(1); } } if (FD_ISSET(sesja->fd, &rd) || FD_ISSET(sesja->fd, &wd)) { struct gg_event *zdarzenie; zdarzenie = gg_watch_fd(sesja); if (!zdarzenie) { błąd("Połączenie przerwane"); gg_free_session(sesja); exit(1); } switch (zdarzenie->type) { case GG_EVENT_CONN_SUCCESS: informacja("Połączono"); break; case GG_EVENT_CONN_FAILED: błąd("Nie można się połączyć"); gg_event_free(zdarzenie); gg_free_session(sesja); exit(1); // ... } gg_event_free(zdarzenie); } }
gg_ping()
.Typ zdarzenia | Pole | Typ pola | Opis |
---|---|---|---|
| - | - | Nie wydarzyło się nic wartego uwagi. |
Zdarzenia związane z połączeniem | |||
| - | - | Połączono z serwerem. Pierwszą rzeczą, jaką należy zrobić jest wysłanie listy kontaktów. |
|
| Nie udało się połączyć. | |
| - | - | Utrzymanie połączenia. Obecnie serwer nie wysyła już do klienta ramek utrzymania połączenia, polega wyłącznie na wysyłaniu ramek przez klienta. |
| - | - | Serwer zrywa połączenie. Zdarza się, gdy równolegle do serwera podłączy się druga sesja i trzeba zerwać połączenie z pierwszą. |
Wiadomości | |||
|
| Otrzymano komunikat systemowy (7.7). | |
|
| Otrzymano wiadomość. Przekazuje również wiadomości systemowe od numeru 0. | |
|
| Potwierdzenie doręczenia wiadomości. | |
|
| Żądanie przesłania obrazka z wiadommości. | |
|
| Przysłano obrazek z wiadomości. | |
Lista kontaktów | |||
|
| Informacja o statusach osób z listy kontaktów (przed 6.0). Zdarzenie należy obsługiwać, jeśli planuje się używać protokołu w wersji starszej niż domyślna. | |
|
| Informacja o statusie opisowym osoby z listy kontaktów (przed 6.0). Zdarzenie należy obsługiwać, jeśli planuje się używać protokołu w wersji starszej niż domyślna. | |
|
| Zmiana statusu osoby z listy kontaktów (przed 6.0). Zdarzenie należy obsługiwać, jeśli planuje się używać protokołu w wersji starszej niż domyślna. | |
|
| Informacja o statusach osób z listy kontaktów. | |
|
| Zmiana statusu osoby z listy kontaktów. | |
|
| Wynik importu lub eksportu listy kontaktów. | |
Katalog publiczny | |||
|
| Odpowiedź katalogu publicznego. | |
|
| Odczytano własne dane z katalogu publicznego. | |
|
| Zmieniono własne dane w katalogu publicznym. | |
Połączenia bezpośrednie | |||
|
| Nowe połączenie bezpośrednie (7.x). | |
|
| Zaakceptowano połączenie bezpośrednie (7.x), nowy deskryptor. | |
|
| Odrzucono połączenie bezpośrednie (7.x). | |
|
| Błąd połączenia bezpośredniego (7.x). |
enum gg_check_t |
enum gg_event_t |
Rodzaj zdarzenia.
void gg_event_free | ( | struct gg_event * | e | ) |
Zwalnia pamięć zajmowaną przez informację o zdarzeniu.
Funkcję należy wywoływać za każdym razem gdy funkcja biblioteki zwróci strukturę gg_event
.
e | Struktura zdarzenia |
struct gg_event* gg_watch_fd | ( | struct gg_session * | sess | ) | [read] |
Funkcja wywoływana po zaobserwowaniu zmian na deskryptorze sesji.
Funkcja zwraca strukturę zdarzenia gg_event
. Jeśli rodzaj zdarzenia to GG_EVENT_NONE
, nie wydarzyło się jeszcze nic wartego odnotowania. Strukturę zdarzenia należy zwolnić funkcja gg_event_free()
.
sess | Struktura sesji |
NULL
jeśli wystąpił błąd