libgadu 1.12.2

- Strona główna
- Dodatkowe strony
- Moduły
- Struktury Danych
- Pliki

Struktury danych | Funkcje
Połączenia bezpośrednie do wersji Gadu-Gadu 6.x
Połączenia bezpośrednie między klientami

## Struktury danych
struct | gg_dcc
| Połączenie bezpośrednie do wersji Gadu-Gadu 6.x. Więcej...

## Funkcje
int | gg_dcc_request (struct gg_session *sess, uin_t uin)
| Wysyła żądanie zwrotnego połączenia bezpośredniego. Więcej...
int | gg_dcc_fill_file_info (struct gg_dcc *d, const char *filename)
| Wypełnia pola struktury `gg_dcc` niezbędne do wysłania pliku. Więcej...
int | gg_dcc_fill_file_info2 (struct gg_dcc *d, const char *filename, const char *local_filename)
| Wypełnia pola struktury `gg_dcc` niezbędne do wysłania pliku. Więcej...
struct gg_dcc * | gg_dcc_get_file (uint32_t ip, uint16_t port, uin_t my_uin, uin_t peer_uin)
| Rozpoczyna odbieranie pliku przez zwrotne połączenie bezpośrednie. Więcej...
struct gg_dcc * | gg_dcc_send_file (uint32_t ip, uint16_t port, uin_t my_uin, uin_t peer_uin)
| Rozpoczyna wysyłanie pliku. Więcej...
struct gg_dcc * | gg_dcc_voice_chat (uint32_t ip, uint16_t port, uin_t my_uin, uin_t peer_uin)
| Rozpoczyna połączenie głosowe. Więcej...
void | gg_dcc_set_type (struct gg_dcc *d, int type)
| Ustawia typ przychodzącego połączenia bezpośredniego. Więcej...
struct gg_dcc * | gg_dcc_socket_create (uin_t uin, uint16_t port)
| Tworzy gniazdo nasłuchujące dla połączeń bezpośrednich. Więcej...
int | gg_dcc_voice_send (struct gg_dcc *d, char *buf, int length)
| Wysyła ramkę danych połączenia głosowego. Więcej...
struct gg_event * | gg_dcc_watch_fd (struct gg_dcc *h)
| Funkcja wywoływana po zaobserwowaniu zmian na deskryptorze połączenia. Więcej...
void | gg_dcc_free (struct gg_dcc *d)
| Zwalnia zasoby używane przez połączenie bezpośrednie. Więcej...

## Opis szczegółowy

Nota
  Funkcje opisane poniżej są zgodne ze starą wersją Gadu-Gadu. Nowy sposób przesyłania plików i przeprowadzania rozmów głosowych, wprowadzony w Gadu-Gadu 7.x, obsługiwany jest innymi funkcjami.

Gadu-Gadu, w przeciwieństwie do protokołów takich jak IRC, umożliwia połączenia w obie strony, bez względu na to, który klient nadaje, a który odbiera. Do tego, jeśli obie strony łączą się do serwera z tego samego publicznego adresu IP, serwer przesyła im ich adresy lokalne.

Ze względu na kierunek i sposób połączenia, wyróżniamy kilka sytuacji:

- Mamy publiczny lub niepubliczny adres IP i chcemy wysłać plik do osoby z publicznym adresem – łączymy się z jego klientem, przedstawiamy się, mówimy czego chcemy i jeśli druga strona to zaakceptuje, zaczynam wysyłać plik. Przypomina zwykłe połączenia DCC klientów IRC.
- Mamy publiczny adres IP i wysyłam plik do kogoś za NAT – wysyłamy na jego numer odpowiednią wiadomość przeznaczoną dla klienta (klasa `GG_CLASS_CTCP`). Druga strona po odebraniu takiego pakietu łączy się znaku o kodzie `0x02`. druga strona, odebrawszy taki pakiet łączy się z nami, mówi, że proszono ją o połączenie i czeka na dalsze instrukcje. My wtedy wysyłamy informację, że owszem, chcemy wysłać plik, mówimy jaki i jeśli druga strona to zaakceptuje, nadajemy.
- Mamy niepubliczny adres IP, tak samo jak i druga strona – tutaj nawiązanie połączenia jest możliwe tylko i wyłącznie, gdy oba klienty znajdują się w tej samej sieci (tj. oba łączą się z serwerem z tego samego adresu zewnętrznego) i wygląda to wtedy identycznie jak w punkcie pierwszym.

To, czy możemy się z kimś połączyć widać po porcie połączeń bezpośrednich drugiej strony, jaki dostajemy w zdarzeniach o zmianie statusu. Jeśli port jest niższy od 10, połączenie nie jest możliwe i należy wysłać specjalną wiadomość za pomocą funkcji `gg_dcc_request()`.

Każde połączenie bezpośrednie i gniazdo nasłuchujące opisywane jest przez strukturę `gg_dcc`. To ostatnie możemy stworzyć za pomocą:

struct gg_dcc *gniazdo;
gniazdo = gg_dcc_socket_create(numer_gg, port_nasłuchujący);
if (!gniazdo)
błąd("Nie można utworzyć gniazda");
dodaj_do_obserwowanych(gniazdo);

Jeśli podamy port 0, libgadu spróbuje znaleźć pierwszy wolny port w okolicy domyślnego portu połączeń bezpośrednich. W przypadku powodzenia zwraca zaalokowaną strukturę `gg_dcc`, której najbardziej interesującym polem `port` zawierające numer przyznanego portu. Jeśli zwróci `NULL`, w zmiennej systemowej `errno` znajdzie się powód błędu: `EINVAL` to niewłaściwie parametry, `ENOMEM` to brak pamięci, a reszta możliwych błędów to błędy związane z gniazdami, np. `EADDRINUSE` gdy nie można znaleźć wolnego portu.

Następnie należy w zmiennej globalnej `gg_dcc_port` ustawić zaalokowany port, do zmiennej `gg_dcc_ip` wpisać publiczny adres IP i połączyć się z serwerem, żeby poinformować świat o swoich namiarach. Jeśli publiczny adres IP to `255.255.255.255`, automatycznie jest przypisywany adres IP, z którego wychodzi połączenie do serwera. Należy pamiętać, że wartości tych zmiennych są używane przez `gg_login()`, więc ich wartości trzeba ustawić przez połączeniem.

Po połączeniu obserwujemy deskryptor gniazda nasłuchującego i gdy coś się pojawi, wywołujemy:

struct gg_event *zdarzenie;
zdarzenie = gg_dcc_watch_fd(gniazdo);
if (!zdarzenie) {
usuń_z_obserwowanych(gniazdo);
gg_dcc_free(gniazdo);
błąd("Poważny błąd!");
}

Błąd jest zwracany tylko w naprawdę krytycznych sytuacjach, gdy brakuje pamięci, lub nie powiodła się operacja na gniazdach, która nie miała się nie powieść (i przy okazji dalsza praca jest kompletnie bezcelowa).

Jeśli błędu nie będzie, dostaniemy informacje o zdarzeniu. W przypadku `GG_SESSION_DCC_SOCKET` mogą to być:

- `GG_EVENT_NONE` – nic ciekawego się nie wydarzyło.
- `GG_EVENT_DCC_ERROR` – wystąpił błąd, którego kod znajduje się w polu `dcc_error` struktury zdarzenia. W przypadku tego typu sesji możliwy jest tylko G`G_ERROR_DCC_HANDSHAKE`, który mówi, że nie udało się porozumieć z klientem, który się połączył.
- `GG_EVENT_DCC_NEW` – nowe połączenie bezpośrednie. W polu `dcc_new` struktury zdarzenia jest struktura `gg_dcc` typu `GG_SESSION_DCC`, którą dodajemy do listy obserwowanych.

W każdym z tych wypadków należy po sprawdzeniu zdarzenia wywołać funkcję...

gg_event_free(zdarzenie);

...by zwolnić pamięć po zdarzeniu.

Gdy nadejdzie połączenie i dopiszemy je do listy obserwowanych, należy zwracać uwagę na następujące zdarzenia:

- `GG_EVENT_NONE` – nic się nie zdarzyło.
- `GG_EVENT_DCC_CLIENT_ACCEPT` – klient się przedstawił i czeka na autoryzację połączenia. Sprawdzamy w strukturze `gg_dcc` pole `uin` jest naszym numerem, a `peer_uin` jest na naszej liście kontaktów i czy chcemy z nim nawiązywać połączenie. Jeśli nie, to po prostu usuwamy połączenie:
  if (!połączenie_dozwolone(dcc->uin, dcc->peer_uin)) {
  usuń_z_obserwowanych(dcc);
  gg_dcc_free(dcc);
  }
- `GG_EVENT_DCC_CALLBACK` – poprosiliśmy klienta, żeby się z nami połączył za pomocą gg_dcc_request() i on teraz pyta się, czego chcemy. Zaraz po tym zdarzeniu należy wywołać funkcję:
  gg_dcc_set_type(dcc, rodzaj);
  gdzie `connection_type` to `GG_SESSION_DCC_SEND` lub `GG_SESSION_DCC_VOICE`. Jeśli wysyłamy plik, można od razu wywołać `gg_dcc_fill_file_info()`, ale nie jest to wymagane. Kiedy przyjdzie pora, biblioteka sama nas o to poprosi.
- `GG_EVENT_DCC_NEED_FILE_ACK` – klient chce wysłać nam plik. W polu `file_info` struktury `gg_dcc` znajdują się wszystkie informacje na temat pliku, jak jego nazwa, rozmiar, atrybuty, data i czas utworzenia itp. Jeśli nie chcemy pliku, zamykamy połączenie w podobny sposób jak przy braku autoryzacji – zamykamy połączenie, ponieważ biblioteka nie potrafi odpowiadać negatywnie na prośby połączeń bezpośrednich. Jeśli plik nas interesuje, otwieramy lokalnie plik do zapisu i numer jego deskryptora zapisujemy do `file_fd` w strukturze `gg_dcc`. Jeśli chcemy wznowić przerwany transfer, otwieramy plik w trybie dopisywania i do pola `offset` wpisujemy ile bajtów już mamy. Biblioteka dalej się wszystkim zajmie.
- `GG_EVENT_DCC_NEED_FILE_INFO` – wcześniej poprosiliśmy drugą stronę by się z nami połączyła, bo jest za NAT, a my chcemy wysłać plik. Możemy albo sami wypełnić strukturę `file_info`, którą biblioteka wyśle drugiej stronie, albo skorzystać z funkcji `gg_dcc_fill_file_info()`.
  if (gg_dcc_fill_file_info(dcc, nazwa_pliku)) {
  błąd("Nie można otworzyć pliku");
  usuń_z_obserwowanych(dcc);
  gg_dcc_free(dcc);
  }
- `GG_EVENT_DCC_DONE` – zakończono transfer. Można przestać obserwować deskryptor i zwolnić zasoby po połączeniu.
- `GG_EVENT_DCC_ERROR` – błąd. Możliwy kod błędu to `GG_ERROR_DCC_HANDSHAKE`, gdy nie powiodło się ustanowienie połączenia z klientem, `GG_ERROR_DCC_NET` kiedy nie udało się wysłać lub odczytać czegoś z gniazda, `GG_ERROR_DCC_FILE` gdy nie można było odczytać albo zapisać do pliku, `GG_ERROR_DCC_EOF` gdy plik lub połączenie zbyt wcześnie się skończy, `GG_ERROR_DCC_REFUSED` gdy użytkownik po drugiej stronie odmówił połączenia.

Tutaj również należy pamiętać o wywoływaniu `gg_event_free()`.

Jeśli chcemy sami wysłać plik, sprawdzamy najpierw, czy druga strona może przyjąć połączenie, patrząc na jej port. Jeśli jest wyższy niż 10, możemy śmiało wywołać funkcję:

struct gg_dcc *dcc;
dcc = gg_dcc_send_file(adres_odbiorcy, port_odbiorcy, numer_wlasny, numer_odbiorcy);
if (!dcc)
błąd("Nie można ustanowić połączenia");

Zaraz potem możemy wywołać funkcję `gg_dcc_fill_file_info()`, by uzupełnić informację o pliku...

gg_dcc_fill_file_info(conn, filename);

...ale jeśli tego nie zrobimy teraz, biblioteka poprosi nas o to w odpowiedniej za pomocą zdarzenia `GG_EVENT_DCC_NEED_FILE_INFO`.

Jeśli port jest podejrzanie niski, znaczy że połączenie jest niemożliwe i wtedy wywołujemy funkcję:

gg_dcc_request(sesja, numer_odbiorcy);

gdzie `session` to nasza sesja Gadu-Gadu (musi być połączona), a `peer_uin` to numer drugiej strony. Wiadomość spowoduje, że druga strona spróbuje się z nami połączyć, jeśli ma taką możliwość.

Gdy otrzymamy wiadomość klasy `GG_CLASS_CTCP` o treści składającej się z bajtu 0x02 znaczy, że ktoś chce nam coś przesłać i mamy się z nim połączyć. Wywołujemy wtedy:

struct gg_dcc *dcc;
dcc = gg_dcc_get_file(adres_nadawcy, port_nadawcy, numer_wlasny, numer_nadawcy);
if (!dcc)
błąd("Nie można ustanowić połączenia");

Dalej tak samo, jak przy zwykłym odbieraniu pliku.

## Dokumentacja funkcji

int gg_dcc_request | ( | struct gg_session * | sess,
|  | uin_t | uin
| ) |  |

Wysyła żądanie zwrotnego połączenia bezpośredniego.

Funkcję wykorzystuje się, jeśli nie ma możliwości połączenia się z odbiorcą pliku lub rozmowy głosowej. Po otrzymaniu żądania druga strona spróbuje nawiązać zwrotne połączenie bezpośrednie z nadawcą. gg_dcc_request()

Parametry

  sess | Struktura sesji
  uin | Numer odbiorcy

Zwraca
  Patrz `gg_send_message_ctcp()`

int gg_dcc_fill_file_info | ( | struct gg_dcc * | d,
|  | const char * | filename
| ) |  |

Wypełnia pola struktury `gg_dcc` niezbędne do wysłania pliku.

Nota
  Większą funkcjonalność zapewnia funkcja `gg_dcc_fill_file_info2()`.

Parametry

  d | Struktura połączenia
  filename | Nazwa pliku

Zwraca
  0 jeśli się powiodło, -1 w przypadku błędu

int gg_dcc_fill_file_info2 | ( | struct gg_dcc * | d,
|  | const char * | filename,
|  | const char * | local_filename
| ) |  |

Wypełnia pola struktury `gg_dcc` niezbędne do wysłania pliku.

Parametry

  d | Struktura połączenia
  filename | Nazwa pliku zapisywana w strukturze
  local_filename | Nazwa pliku w lokalnym systemie plików

Zwraca
  0 jeśli się powiodło, -1 w przypadku błędu

struct gg_dcc* gg_dcc_get_file | ( | uint32_t | ip,
|  | uint16_t | port,
|  | uin_t | my_uin,
|  | uin_t | peer_uin
| ) |  |

Rozpoczyna odbieranie pliku przez zwrotne połączenie bezpośrednie.

Parametry

  ip | Adres IP nadawcy
  port | Port nadawcy
  my_uin | Własny numer
  peer_uin | Numer nadawcy

Zwraca
  Struktura `gg_dcc` lub `NULL` w przypadku błędu

struct gg_dcc* gg_dcc_send_file | ( | uint32_t | ip,
|  | uint16_t | port,
|  | uin_t | my_uin,
|  | uin_t | peer_uin
| ) |  |

Rozpoczyna wysyłanie pliku.

Parametry

  ip | Adres IP odbiorcy
  port | Port odbiorcy
  my_uin | Własny numer
  peer_uin | Numer odbiorcy

Zwraca
  Struktura `gg_dcc` lub `NULL` w przypadku błędu

struct gg_dcc* gg_dcc_voice_chat | ( | uint32_t | ip,
|  | uint16_t | port,
|  | uin_t | my_uin,
|  | uin_t | peer_uin
| ) |  |

Rozpoczyna połączenie głosowe.

Parametry

  ip | Adres IP odbiorcy
  port | Port odbiorcy
  my_uin | Własny numer
  peer_uin | Numer odbiorcy

Zwraca
  Struktura `gg_dcc` lub `NULL` w przypadku błędu

void gg_dcc_set_type | ( | struct gg_dcc * | d,
|  | int | type
| ) |  |

Ustawia typ przychodzącego połączenia bezpośredniego.

Funkcję należy wywołać po otrzymaniu zdarzenia `GG_EVENT_DCC_CALLBACK`.

Parametry

  d | Struktura połączenia
  type | Rodzaj połączenia (`GG_SESSION_DCC_SEND` lub `GG_SESSION_DCC_VOICE`)

struct gg_dcc* gg_dcc_socket_create | ( | uin_t | uin,
|  | uint16_t | port
| ) |  |

Tworzy gniazdo nasłuchujące dla połączeń bezpośrednich.

Funkcja przywiązuje gniazdo do pierwszego wolnego portu TCP.

Parametry

  uin | Własny numer
  port | Preferowany port (jeśli równy 0 lub -1, próbuje się domyślnego)

Nota
  Ze względu na możliwość podania wartości -1 do parametru będącego 16-bitową liczbą bez znaku, port 65535 nie jest dostępny.

Zwraca
  Struktura `gg_dcc` lub `NULL` w przypadku błędu

int gg_dcc_voice_send | ( | struct gg_dcc * | d,
|  | char * | buf,
|  | int | length
| ) |  |

Wysyła ramkę danych połączenia głosowego.

Parametry

  d | Struktura połączenia
  buf | Bufor z danymi
  length | Długość bufora z danymi

Zwraca
  0 jeśli się powiodło, -1 w przypadku błędu

struct gg_event* gg_dcc_watch_fd | ( | struct gg_dcc * | h | ) |

Funkcja wywoływana po zaobserwowaniu zmian na deskryptorze połączenia.

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`.

Parametry

  h | Struktura połączenia

Zwraca
  Struktura zdarzenia lub `NULL` jeśli wystąpił błąd

void gg_dcc_free | ( | struct gg_dcc * | d | ) |

Zwalnia zasoby używane przez połączenie bezpośrednie.

Parametry

  d | Struktura połączenia