#ifndef SML3__NW_MBCAST_H_
#define SML3__NW_MBCAST_H_

/* ++++++++++++++++++++
 * +++ Beschreibung +++
 * ++++++++++++++++++++

  Broadcast- und Multicast-Server und -Client
+++ */


/* ++++++++++++++++
 * +++ Beispiel +++
 * ++++++++++++++++

  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <sys/types.h>
  #include <unistd.h>
  #include <errno.h>
  #include <sammel3.h>

  // Auswerte-Funktion fuer Server
  int svfk(void *vptr, const char *ipnr, char *daten, size_t *len) {
    char *cptr = (char *)vptr;  // 5.Arg von SML3_nw_mbcast_server()
    char buf[SML3_NW_MBCAST_MAXDATA];
    // Rueckgabepaket erstellen
    snprintf(buf, sizeof(buf), "%s: Paket von [%s]: \"%.*s\"", cptr, ipnr, (int)*len, daten);
    *len = strlen(buf);  // Laenge des zurueckzusendenen Pakets
    memmove(daten, buf, *len);
    return 1;  // Antwort senden
  }

  int main(int argc, char **argv) {
    const char *port = "1234";
    const char *daten = "Ist hier jemand?";
    struct SML3_nw_mbcast *ipliste, *ipptr;
    int anz, istegal;

    // Broadcast- und Multicast-Server im Hintergrund starten
    if (SML3_nw_mbcast_server(port, 4, &istegal, svfk, "Broadcast-Server") < 0) { fprintf(stderr, "%s\n", SML3_fehlermsg()); exit(1); }
    if (SML3_nw_mbcast_server(port, 6, &istegal, svfk, "Multicast-Server") < 0) { fprintf(stderr, "%s\n", SML3_fehlermsg()); exit(1); }

    // Anfrage ueber alle Schnittstellen via Broadcast und Multicast stellen
    anz = SML3_nw_mbcast_client(NULL, port, 0, 5, daten, strlen(daten), &ipliste);
    if (anz < 0) { fprintf(stderr, "%s\n", SML3_fehlermsg()); exit(1); }
    printf("%d Antworten\n", anz);

    // Antwort-Liste ausgeben
    for (ipptr = ipliste; ipptr != NULL; ipptr = ipptr->next) {
      printf("IPv%d: von %s (%s): [%.*s]\n", ipptr->ipv, ipptr->ipnr, ipptr->iface, (int)ipptr->datlen, ipptr->daten);
    }

    // Antwort-Liste freigeben
    SML3_nw_mbcast_free(ipliste);

    // die Server beenden sich automatisch
    exit(0);
  }
+++ */


/* ++++++++++++++++++ */
/* +++ Funktionen +++ */
/* ++++++++++++++++++ */

#define SML3_NW_MBCAST_MAXDATA 512

struct SML3_nw_mbcast {  /* Antwort-Struct fuer Client */
  struct SML3_nw_mbcast *next;         /* naechstes Element oder NULL = Ende */
  int ipv;                             /* IP-Version: 4 oder 6 */
  char ipnr[64];                       /* IP-Nummer */
  char iface[32];                      /* Interface-Name (leer bei BC=255.255.255.255) */
  char daten[SML3_NW_MBCAST_MAXDATA];  /* empfangene Daten */
  size_t datlen;                       /* Anzahl Bytes der empfangenen Daten */
};


/** SML3_nw_mbcast_server [ohne Auswerte-Funktion: thread-sicher]:
 * Broadcast- bzw. Multicast-Server
 * 1.Arg: Servicename oder Port
 * 2.Arg: IP-Version
 *        4 = IPv4  (Broadcast-Server)
 *        6 = IPv6  (Multicast-Server)
 * 3.Arg: nicht NULL: Pipe erstellen, forken und Pipe-Schreibende zurueckgeben
 *                    (wenn Pipe-Schreibende geschlossen wird, beendet sich der Server)
 *              NULL: nicht forken
 * 4.Arg: Auswerte-Funktion fuer empfangene Broadcast- bzw. Multicast-Anfragen
 *          int funktion(void *vptr, const char *ipnr, char *daten, size_t *len)
 *            (erhaelt in "ipnr" die Remote-IP
 *             erhaelt in "daten" empfangene Daten mit Byteanzahl "len"
 *             setzt zu sendende Daten in "daten" (mit Maximalanzahl SML3_NW_MBCAST_MAXDATA Bytes)
 *               und neue Byteanzahl in "len"
 *             gibt zurueck: 1 = Antwort senden oder 0 = nicht senden
 *            )
 *        oder NULL = keine (sendet Antwort)
 * 5.Arg: 1.Arg der Funktion (siehe 4.Arg) oder NULL
 * Rueckgabe: >=0 = OK  (bei Fork: Server-PID, ansonsten 0)
 *             -1 = Fehler
 * SML3-errno-Wert: EINVAL = Fehler Uebergabeparameter
 *                  EAFNOSUPPORT = IPv6 nicht verfuegbar
 *                  ENOENT = Fehler bei pipe()
 *                  ECHILD = Fehler bei fork()
 *                  ENOMEM = Allokationsfehler
 *                  EIO = Fehler bei select()
 *                  weitere aus SML3_nw_udp_server()
 */
extern int SML3_nw_mbcast_server(const char *, int, int *, int (*)(void *, const char *, char *, size_t *), void *);


/** SML3_nw_mbcast_client [ohne Auswerte-Funktion: thread-sicher]:
 * Broadcast- bzw. Multicast-Client
 * versendet Datenpaket via Broadcast- bzw. Multicast und empfaengt Antworten
 * 1.Arg: Name des zu verwendenden Interfaces (ohne Alias-Erweiterung) oder NULL = alle
 * 2.Arg: Servicename oder Port
 * 3.Arg: IP-Version
 *         4 = IPv4  (Broadcast)
 *        44 = IPv4  (falls 1.Arg = NULL: Broadcast zusaetzlich an 255.255.255.255)
 *         6 = IPv6  (Multicast)
 *         0 = egal  (Broadcast + Multicast)
 * 4.Arg: Timeout in Sekunden fuer Warten auf Antworten
 *        oder 0 = nach erster Antwort abbrechen (Timeout ist 5 Sekunden)
 * 5.Arg: zu versendende Daten (beschraenkt auf SML3_NW_MBCAST_MAXDATA Bytes)
 *        oder NULL = egal
 * 6.Arg: Byteanzahl im 5.Arg
 *        oder 0, wenn 5.Arg = NULL
 * 7.Arg: fuer Rueckgabe Antworten (verkettete Liste), ist mit SML3_nw_mbcast_free() freizugeben
 * Rueckgabe: >=0: OK (Anzahl Antworten) oder -1 = Fehler
 * SML3-errno-Wert: EINVAL = Fehler Uebergabeparameter
 *                  EAFNOSUPPORT = IPv6 nicht verfuegbar
 *                  ENOMEM = Allokationsfehler
 *                  EIO = Fehler bei select()
 *                  weitere aus SML3_nw_if_get()
 */
extern int SML3_nw_mbcast_client(const char *, const char *, int, int, const void *, size_t, struct SML3_nw_mbcast **);


/** SML3_nw_mbcast_free: [thread-sicher]
 * gibt mit SML3_nw_mbcast_client() erstellte Antwort-Liste frei
 * 1.Arg: Antwort-Liste
 */
extern void SML3_nw_mbcast_free(struct SML3_nw_mbcast *);

#endif /* SML3__NW_MBCAST_H_ */
