/* Copyright 2022-2026 Kurt Nienhaus
 *
 * This file is part of VgaGames.
 * VgaGames is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 * VgaGames is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with VgaGames.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <syslog.h>
#include "nw.h"

void sv_dgram2nwpack(const char *, const unsigned char *, size_t, struct nwdata_packets *);
size_t sv_nwpack2dgram(const char *, const struct nwdata_packets *, unsigned char *, int);


/* set data in dgram to nwpack */
void
sv_dgram2nwpack(const char *remaddr, const unsigned char *dgram, size_t slen, struct nwdata_packets *nwpack)
{
  size_t tlen;
#ifdef NWPACK_DUMP
  char rembuf[160];
#endif

  if (dgram == NULL || nwpack == NULL) { return; }
  (void)remaddr;
#ifdef NWPACK_DUMP
  if (remaddr != NULL) {
    snprintf(rembuf, sizeof(rembuf), " [%s]", remaddr);
  } else {
    *rembuf = '\0';
  }
#endif
  memset(nwpack, 0, sizeof(*nwpack));
  if (slen > NW_MAXPAKET) { return; }  /* too big */
  if (slen < 2) { return; }  /* kenner and action */

  /* read kenner and action */
  nwpack->kenner = (int)dgram[0];
  nwpack->action = (int)dgram[1];
  dgram += 2; slen -= 2;

  if (nwpack->kenner == NWDATA_KENNER_GETCONN) {  /* get connections */

    if (nwpack->action == NWDATA_ACTION_NEWCONN) {  /* new connection */
      /* read 1 byte: maxclients */
      if (slen == 0) {
        outlog(LOG_WARNING, "sv_dgram2nwpack(k=%d, a=%d): read maxclients: out of data", nwpack->kenner, nwpack->action);
        goto end_d2n;
      }
      nwpack->u.k_getconn.a_newconn.c2s.maxcl = (int)dgram[0];
      dgram++; slen--;

      /* read rest of bytes: nulltermintated hostname */
      tlen = sizeof(nwpack->u.k_getconn.a_newconn.c2s.hname);
      if (slen == 0) {
        outlog(LOG_WARNING, "sv_dgram2nwpack(k=%d, a=%d): read hostname: out of data", nwpack->kenner, nwpack->action);
        goto end_d2n;
      }
      if (slen > tlen) { slen = tlen; }
      memcpy(nwpack->u.k_getconn.a_newconn.c2s.hname, dgram, slen);
      nwpack->u.k_getconn.a_newconn.c2s.hname[tlen - 1] = '\0';
      slen = 0;
#ifdef NWPACK_DUMP
      fprintf(stderr, "TO-SV%s: GETCONN-NEWCONN:\n", rembuf);
      fprintf(stderr, " - maxcl: %d\n", nwpack->u.k_getconn.a_newconn.c2s.maxcl);
      fprintf(stderr, " - hname: \"%s\"\n", nwpack->u.k_getconn.a_newconn.c2s.hname);
#endif

    } else if (nwpack->action == NWDATA_ACTION_ENDCONN) {  /* end getting connections */
      /* no data */
      if (slen > 0) { outlog(LOG_WARNING, "sv_dgram2nwpack(k=%d, a=%d): extra data of %d bytes", nwpack->kenner, nwpack->action, (int)slen); }
#ifdef NWPACK_DUMP
      fprintf(stderr, "TO-SV%s: GETCONN-ENDCONN: (no data)\n", rembuf);
#endif

    } else {  /* unknown */
      outlog(LOG_WARNING, "sv_dgram2nwpack(k=%d): invalid action: %d", nwpack->kenner, nwpack->action);
      goto end_d2n;
    }

  } else if (nwpack->kenner == NWDATA_KENNER_RUNCONN) {  /* run connections */

    if (nwpack->action == NWDATA_ACTION_CLOSE) {  /* close */
      /* read 1 byte: client-number */
      if (slen == 0) {
        outlog(LOG_WARNING, "sv_dgram2nwpack(k=%d, a=%d): read client-number: out of data", nwpack->kenner, nwpack->action);
        goto end_d2n;
      }
      nwpack->u.k_runconn.a_close.c2s.clnr = (int)dgram[0];
      dgram++; slen--;

      /* done */
      if (slen > 0) {
        outerr("sv_dgram2nwpack(k=%d, a=%d): extra data of %d bytes", nwpack->kenner, nwpack->action, (int)slen);
      }
#ifdef NWPACK_DUMP
      fprintf(stderr, "TO-SV%s: RUNCONN-CLOSE:\n", rembuf);
      fprintf(stderr, " - clnr: %d\n", nwpack->u.k_runconn.a_close.c2s.clnr);
#endif

    } else if (nwpack->action == NWDATA_ACTION_PING) {  /* ping */
      /* read 1 byte: client-number */
      if (slen == 0) {
        outlog(LOG_WARNING, "sv_dgram2nwpack(k=%d, a=%d): read client-number: out of data", nwpack->kenner, nwpack->action);
        goto end_d2n;
      }
      nwpack->u.k_runconn.a_ping.c2s.clnr = (int)dgram[0];
      dgram++; slen--;

      /* done */
      if (slen > 0) {
        outerr("sv_dgram2nwpack(k=%d, a=%d): extra data of %d bytes", nwpack->kenner, nwpack->action, (int)slen);
      }
#ifdef NWPACK_DUMP
      fprintf(stderr, "TO-SV%s: RUNCONN-PING:\n", rembuf);
      fprintf(stderr, " - clnr: %d\n", nwpack->u.k_runconn.a_ping.c2s.clnr);
#endif

    } else if (nwpack->action == NWDATA_ACTION_PAUSE) {  /* pause */
      /* read 1 byte: client-number */
      if (slen == 0) {
        outlog(LOG_WARNING, "sv_dgram2nwpack(k=%d, a=%d): read client-number: out of data", nwpack->kenner, nwpack->action);
        goto end_d2n;
      }
      nwpack->u.k_runconn.a_pause.c2s.clnr = (int)dgram[0];
      dgram++; slen--;

      /* done */
      if (slen > 0) {
        outerr("sv_dgram2nwpack(k=%d, a=%d): extra data of %d bytes", nwpack->kenner, nwpack->action, (int)slen);
      }
#ifdef NWPACK_DUMP
      fprintf(stderr, "TO-SV%s: RUNCONN-PAUSE:\n", rembuf);
      fprintf(stderr, " - clnr: %d\n", nwpack->u.k_runconn.a_pause.c2s.clnr);
#endif

    } else if (nwpack->action == NWDATA_ACTION_CONTINUE) {  /* continue */
      /* read 1 byte: client-number */
      if (slen == 0) {
        outlog(LOG_WARNING, "sv_dgram2nwpack(k=%d, a=%d): read client-number: out of data", nwpack->kenner, nwpack->action);
        goto end_d2n;
      }
      nwpack->u.k_runconn.a_continue.c2s.clnr = (int)dgram[0];
      dgram++; slen--;

      /* done */
      if (slen > 0) {
        outerr("sv_dgram2nwpack(k=%d, a=%d): extra data of %d bytes", nwpack->kenner, nwpack->action, (int)slen);
      }
#ifdef NWPACK_DUMP
      fprintf(stderr, "TO-SV%s: RUNCONN-CONTINUE:\n", rembuf);
      fprintf(stderr, " - clnr: %d\n", nwpack->u.k_runconn.a_continue.c2s.clnr);
#endif

    } else if (nwpack->action == NWDATA_ACTION_KEYS) {  /* keys */
      /* read 1 byte: client-number */
      if (slen == 0) {
        outlog(LOG_WARNING, "sv_dgram2nwpack(k=%d, a=%d): read client-number: out of data", nwpack->kenner, nwpack->action);
        goto end_d2n;
      }
      nwpack->u.k_runconn.a_keys.c2s.clnr = (int)dgram[0];
      dgram++; slen--;

      /* read 2 bytes: sequence-number */
      if (slen < 2) {
        outlog(LOG_WARNING, "sv_dgram2nwpack(k=%d, a=%d): read sequence-number: out of data", nwpack->kenner, nwpack->action);
        goto end_d2n;
      }
      USHORT_SET(nwpack->u.k_runconn.a_keys.c2s.seqnr, dgram[0], dgram[1]);
      dgram += 2; slen -= 2;

      /* read MAX_KEYSBYT bytes: keys-data */
      if (slen < MAX_KEYSBYT) {
        outlog(LOG_WARNING, "sv_dgram2nwpack(k=%d, a=%d): read keys-data: out of data", nwpack->kenner, nwpack->action);
        goto end_d2n;
      }
      memcpy(nwpack->u.k_runconn.a_keys.c2s.keysdata, dgram, MAX_KEYSBYT);
      dgram += MAX_KEYSBYT; slen -= MAX_KEYSBYT;

      /* read 1 byte: length of additional-data */
      if (slen == 0) {
        outlog(LOG_WARNING, "sv_dgram2nwpack(k=%d, a=%d): read additional-data-length: out of data", nwpack->kenner, nwpack->action);
        goto end_d2n;
      }
      nwpack->u.k_runconn.a_keys.c2s.zdatalen = (int)dgram[0];
      dgram++; slen--;

      /* read nwpack->u.k_runconn.a_keys.c2s.zdatalen bytes: additional-data */
      tlen = nwpack->u.k_runconn.a_keys.c2s.zdatalen;
      if (tlen > 0) {
        if (slen < tlen) {
          outlog(LOG_WARNING, "sv_dgram2nwpack(k=%d, a=%d): read additional-data: out of data", nwpack->kenner, nwpack->action);
          goto end_d2n;
        }
        memcpy(nwpack->u.k_runconn.a_keys.c2s.zdata, dgram, tlen);
        dgram += tlen; slen -= tlen;
      }

      /* done */
      if (slen > 0) {
        outerr("sv_dgram2nwpack(k=%d, a=%d): extra data of %d bytes", nwpack->kenner, nwpack->action, (int)slen);
      }
#ifdef NWPACK_DUMP
      fprintf(stderr, "TO-SV%s: RUNCONN-KEYS:\n", rembuf);
      fprintf(stderr, " - clnr: %d\n", nwpack->u.k_runconn.a_keys.c2s.clnr);
      fprintf(stderr, " - seqnr: %d\n", (int)nwpack->u.k_runconn.a_keys.c2s.seqnr);
      fprintf(stderr, " - keysdata: ");
      { int ikey;
        for (ikey = 0; ikey < MAX_KEYSBYT; ikey++) { fprintf(stderr, "%02x", nwpack->u.k_runconn.a_keys.c2s.keysdata[ikey]); }
        fprintf(stderr, "\n");
      }
      fprintf(stderr, " - zdatalen: %d\n", nwpack->u.k_runconn.a_keys.c2s.zdatalen);
      if (nwpack->u.k_runconn.a_keys.c2s.zdatalen > 0) {
        char *bcode;
        SML3_base64_encode(&bcode, NULL, nwpack->u.k_runconn.a_keys.c2s.zdata, nwpack->u.k_runconn.a_keys.c2s.zdatalen, 0, NULL);
        fprintf(stderr, "   - zdata: base64[%s]\n", bcode);
        free(bcode);
      }
#endif

    } else if (nwpack->action == NWDATA_ACTION_CONNECTED) {  /* client wants to receive connected-client-info */
      /* read 1 byte: client-number */
      if (slen == 0) {
        outlog(LOG_WARNING, "sv_dgram2nwpack(k=%d, a=%d): read client-number: out of data", nwpack->kenner, nwpack->action);
        goto end_d2n;
      }
      nwpack->u.k_runconn.a_connected.c2s.clnr = (int)dgram[0];
      dgram++; slen--;

      /* done */
      if (slen > 0) {
        outerr("sv_dgram2nwpack(k=%d, a=%d): extra data of %d bytes", nwpack->kenner, nwpack->action, (int)slen);
      }
#ifdef NWPACK_DUMP
      fprintf(stderr, "TO-SV%s: RUNCONN-CONNECTED:\n", rembuf);
      fprintf(stderr, " - clnr: %d\n", nwpack->u.k_runconn.a_connected.c2s.clnr);
#endif

    } else if (nwpack->action == NWDATA_ACTION_XDATA_RECV) {  /* client wants to receive exchange-data */
      /* read 1 byte: client-number */
      if (slen == 0) {
        outlog(LOG_WARNING, "sv_dgram2nwpack(k=%d, a=%d): read client-number: out of data", nwpack->kenner, nwpack->action);
        goto end_d2n;
      }
      nwpack->u.k_runconn.a_xdata_recv.c2s.clnr = (int)dgram[0];
      dgram++; slen--;

      /* read 2 bytes: sequence-number */
      if (slen < 2) {
        outlog(LOG_WARNING, "sv_dgram2nwpack(k=%d, a=%d): read sequence-number: out of data", nwpack->kenner, nwpack->action);
        goto end_d2n;
      }
      USHORT_SET(nwpack->u.k_runconn.a_xdata_recv.c2s.seqnr, dgram[0], dgram[1]);
      dgram += 2; slen -= 2;

      /* done */
      if (slen > 0) {
        outerr("sv_dgram2nwpack(k=%d, a=%d): extra data of %d bytes", nwpack->kenner, nwpack->action, (int)slen);
      }
#ifdef NWPACK_DUMP
      fprintf(stderr, "TO-SV%s: RUNCONN-XDATA_RECV:\n", rembuf);
      fprintf(stderr, " - clnr: %d\n", nwpack->u.k_runconn.a_xdata_recv.c2s.clnr);
      fprintf(stderr, " - seqnr: %d\n", (int)nwpack->u.k_runconn.a_xdata_recv.c2s.seqnr);
#endif

    } else if (nwpack->action == NWDATA_ACTION_XDATA_SEND) {  /* client sends exchange-data */
      /* read 1 byte: client-number */
      if (slen == 0) {
        outlog(LOG_WARNING, "sv_dgram2nwpack(k=%d, a=%d): read client-number: out of data", nwpack->kenner, nwpack->action);
        goto end_d2n;
      }
      nwpack->u.k_runconn.a_xdata_send.c2s.clnr = (int)dgram[0];
      dgram++; slen--;

      /* read 2 bytes: sequence-number */
      if (slen < 2) {
        outlog(LOG_WARNING, "sv_dgram2nwpack(k=%d, a=%d): read sequence-number: out of data", nwpack->kenner, nwpack->action);
        goto end_d2n;
      }
      USHORT_SET(nwpack->u.k_runconn.a_xdata_send.c2s.seqnr, dgram[0], dgram[1]);
      dgram += 2; slen -= 2;

      /* read 2 bytes: length of exchange-data */
      if (slen < 2) {
        outlog(LOG_WARNING, "sv_dgram2nwpack(k=%d, a=%d): read exchange-data-length: out of data", nwpack->kenner, nwpack->action);
        goto end_d2n;
      }
      USHORT_SET(nwpack->u.k_runconn.a_xdata_send.c2s.xdatalen, dgram[0], dgram[1]);
      dgram += 2; slen -= 2;
      if (nwpack->u.k_runconn.a_xdata_send.c2s.xdatalen > MAX_XDATA) {
        outlog(LOG_WARNING, "sv_dgram2nwpack(k=%d, a=%d): read exchange-data-length: too much bytes (%d > %d)",
               nwpack->kenner, nwpack->action, nwpack->u.k_runconn.a_xdata_send.c2s.xdatalen, MAX_XDATA);
        goto end_d2n;
      }

      /* read nwpack->u.k_runconn.a_xdata_send.c2s.xdatalen bytes: exchange-data */
      tlen = nwpack->u.k_runconn.a_xdata_send.c2s.xdatalen;
      if (tlen > 0) {
        if (slen < tlen) {
          outlog(LOG_WARNING, "sv_dgram2nwpack(k=%d, a=%d): read exchange-data: out of data", nwpack->kenner, nwpack->action);
          goto end_d2n;
        }
        memcpy(nwpack->u.k_runconn.a_xdata_send.c2s.xdata, dgram, tlen);
        dgram += tlen; slen -= tlen;
      }

      /* done */
      if (slen > 0) {
        outerr("sv_dgram2nwpack(k=%d, a=%d): extra data of %d bytes", nwpack->kenner, nwpack->action, (int)slen);
      }
#ifdef NWPACK_DUMP
      fprintf(stderr, "TO-SV%s: RUNCONN-XDATA_SEND:\n", rembuf);
      fprintf(stderr, " - clnr: %d\n", nwpack->u.k_runconn.a_xdata_send.c2s.clnr);
      fprintf(stderr, " - seqnr: %d\n", (int)nwpack->u.k_runconn.a_xdata_send.c2s.seqnr);
      fprintf(stderr, " - xdatalen: %d\n", nwpack->u.k_runconn.a_xdata_send.c2s.xdatalen);
      if (nwpack->u.k_runconn.a_xdata_send.c2s.xdatalen > 0) {
        char *bcode;
        SML3_base64_encode(&bcode, NULL, nwpack->u.k_runconn.a_xdata_send.c2s.xdata, nwpack->u.k_runconn.a_xdata_send.c2s.xdatalen, 0, NULL);
        fprintf(stderr, " - xdata: base64[%s]\n", bcode);
        free(bcode);
      }
#endif

    } else {  /* unknown */
      outlog(LOG_WARNING, "sv_dgram2nwpack(k=%d): invalid action: %d", nwpack->kenner, nwpack->action);
      goto end_d2n;
    }

  } else {  /* unknown */
    outlog(LOG_WARNING, "sv_dgram2nwpack: invalid kenner: %d", nwpack->kenner);
    goto end_d2n;
  }

  return;

end_d2n:
  memset(nwpack, 0, sizeof(*nwpack));
} /* Ende sv_dgram2nwpack */


/* set data in nwpack to dgram for client-number clnr */
size_t
sv_nwpack2dgram(const char *remaddr, const struct nwdata_packets *nwpack, unsigned char *dgram, int clnr)
{
  size_t slen, tlen;
#ifdef NWPACK_DUMP
  unsigned char *dgram0 = dgram;
#endif

  if (nwpack == NULL || dgram == NULL) { return 0; }
  (void)remaddr;

  memset(dgram, 0, NW_MAXPAKET);
  slen = 0;

  /* set kenner and action */
  dgram[0] = (unsigned char)nwpack->kenner;
  dgram[1] = (unsigned char)nwpack->action;
  dgram += 2; slen += 2;

  if (nwpack->kenner == NWDATA_KENNER_GETCONN) {  /* get connections */

    if (nwpack->action == NWDATA_ACTION_NEWCONN) {  /* got new connection */
      /* set 1 byte: bytes of hostnames */
      if (slen + 1 > NW_MAXPAKET) {
        outlog(LOG_WARNING, "sv_nwpack2dgram(k=%d, a=%d): set bytes of hostnames: out of space", nwpack->kenner, nwpack->action);
        goto end_n2d;
      }
      dgram[0] = (unsigned char)nwpack->u.k_getconn.a_newconn.s2c.hnamelen;
      dgram++; slen++;

      /* set hnamelen bytes: hostnames */
      tlen = nwpack->u.k_getconn.a_newconn.s2c.hnamelen;
      if (slen + tlen > NW_MAXPAKET) {
        outlog(LOG_WARNING, "sv_nwpack2dgram(k=%d, a=%d): set hostnames: out of space", nwpack->kenner, nwpack->action);
        goto end_n2d;
      }
      memcpy(dgram, nwpack->u.k_getconn.a_newconn.s2c.hname, tlen);
      dgram += tlen;
      slen += tlen;
#ifdef NWPACK_DUMP
      { struct nwdata_packets nwp; cl_dgram2nwpack(remaddr, dgram0, slen, &nwp); }
#endif

    } else if (nwpack->action == NWDATA_ACTION_ENDCONN) {  /* end getting connections */
      /* set 1 byte: client-number */
      if (slen + 1 > NW_MAXPAKET) {
        outlog(LOG_WARNING, "sv_nwpack2dgram(k=%d, a=%d): set client-number: out of space", nwpack->kenner, nwpack->action);
        goto end_n2d;
      }
      dgram[0] = (unsigned char)clnr;
      dgram++; slen++;

      /* set sizeof(nw_seed) bytes: network-seed */
      tlen = sizeof(nwpack->u.k_getconn.a_endconn.s2c.nw_seed);
      if (slen + tlen > NW_MAXPAKET) {
        outlog(LOG_WARNING, "sv_nwpack2dgram(k=%d, a=%d): set network-seed: out of space", nwpack->kenner, nwpack->action);
        goto end_n2d;
      }
      memcpy(dgram, nwpack->u.k_getconn.a_endconn.s2c.nw_seed, tlen);
      dgram += tlen;
      slen += tlen;

      /* set 1 byte: bytes of hostnames */
      if (slen + 1 > NW_MAXPAKET) {
        outlog(LOG_WARNING, "sv_nwpack2dgram(k=%d, a=%d): set bytes of hostnames: out of space", nwpack->kenner, nwpack->action);
        goto end_n2d;
      }
      dgram[0] = (unsigned char)nwpack->u.k_getconn.a_endconn.s2c.hnamelen;
      dgram++; slen++;

      /* set hnamelen bytes: hostnames */
      tlen = nwpack->u.k_getconn.a_endconn.s2c.hnamelen;
      if (slen + tlen > NW_MAXPAKET) {
        outlog(LOG_WARNING, "sv_nwpack2dgram(k=%d, a=%d): set hostnames: out of space", nwpack->kenner, nwpack->action);
        goto end_n2d;
      }
      memcpy(dgram, nwpack->u.k_getconn.a_endconn.s2c.hname, tlen);
      dgram += tlen;
      slen += tlen;
#ifdef NWPACK_DUMP
      { struct nwdata_packets nwp; cl_dgram2nwpack(remaddr, dgram0, slen, &nwp); }
#endif

    } else {  /* unknown */
      outlog(LOG_WARNING, "sv_nwpack2dgram(k=%d): invalid action: %d", nwpack->kenner, nwpack->action);
      goto end_n2d;
    }

  } else if (nwpack->kenner == NWDATA_KENNER_RUNCONN) {  /* run connections */

    if (nwpack->action == NWDATA_ACTION_CLOSE) {  /* close */
      /* no data */
#ifdef NWPACK_DUMP
      { struct nwdata_packets nwp; cl_dgram2nwpack(remaddr, dgram0, slen, &nwp); }
#endif

    } else if (nwpack->action == NWDATA_ACTION_PAUSE) {  /* pause */
      /* no data */
#ifdef NWPACK_DUMP
      { struct nwdata_packets nwp; cl_dgram2nwpack(remaddr, dgram0, slen, &nwp); }
#endif

    } else if (nwpack->action == NWDATA_ACTION_CONTINUE) {  /* continue */
      /* no data */
#ifdef NWPACK_DUMP
      { struct nwdata_packets nwp; cl_dgram2nwpack(remaddr, dgram0, slen, &nwp); }
#endif

    } else if (nwpack->action == NWDATA_ACTION_KEYS) {  /* keys */
      int istart, ianz;
      size_t pklen = 0;

      istart = 0;
      ianz = nwpack->u.k_runconn.a_keys.s2c.anz;
      while (ianz > 0) {
        /* set 2 bytes: sequence-number */
        if (slen + 2 > NW_MAXPAKET) {
          if (pklen == 0) {
            outlog(LOG_WARNING, "sv_nwpack2dgram(k=%d, a=%d): set sequence-number: out of space", nwpack->kenner, nwpack->action);
            goto end_n2d;
          }
          break;
        }
        USHORT_GET(nwpack->u.k_runconn.a_keys.s2c.data[istart].seqnr, dgram[0], dgram[1]);
        dgram += 2; slen += 2;

        /* set 1 byte: client-connection-bits */
        if (slen + 1 > NW_MAXPAKET) {
          if (pklen == 0) {
            outlog(LOG_WARNING, "sv_nwpack2dgram(k=%d, a=%d): set client-connection-bits: out of space", nwpack->kenner, nwpack->action);
            goto end_n2d;
          }
          break;
        }
        dgram[0] = nwpack->u.k_runconn.a_keys.s2c.data[istart].conncl;
        dgram++; slen++;

        /* set 1 byte: client-keyset-bits */
        if (slen + 1 > NW_MAXPAKET) {
          if (pklen == 0) {
            outlog(LOG_WARNING, "sv_nwpack2dgram(k=%d, a=%d): set client-keyset-bits: out of space", nwpack->kenner, nwpack->action);
            goto end_n2d;
          }
          break;
        }
        dgram[0] = nwpack->u.k_runconn.a_keys.s2c.data[istart].keyset;
        dgram++; slen++;

        /* set MAX_KEYSBYT * MAX_CLIENTS bytes: keys-data for each client */
        tlen = MAX_KEYSBYT * MAX_CLIENTS;
        if (slen + tlen > NW_MAXPAKET) {
          if (pklen == 0) {
            outlog(LOG_WARNING, "sv_nwpack2dgram(k=%d, a=%d): set keys-data: out of space", nwpack->kenner, nwpack->action);
            goto end_n2d;
          }
          break;
        }
        memcpy(dgram, nwpack->u.k_runconn.a_keys.s2c.data[istart].keysdata, tlen);
        dgram += tlen; slen += tlen;

        /* set 1 byte: length of additional-data */
        if (slen + 1 > NW_MAXPAKET) {
          if (pklen == 0) {
            outlog(LOG_WARNING, "sv_nwpack2dgram(k=%d, a=%d): set additional-data-length: out of space", nwpack->kenner, nwpack->action);
            goto end_n2d;
          }
          break;
        }
        dgram[0] = nwpack->u.k_runconn.a_keys.s2c.data[istart].zdatalen;
        dgram++; slen++;

        /* set nwpack->u.k_runconn.a_keys.s2c.data[istart].zdatalen bytes: additional-data */
        tlen = nwpack->u.k_runconn.a_keys.s2c.data[istart].zdatalen;
        if (tlen > 0) {
          if (slen + tlen > NW_MAXPAKET) {
            if (pklen == 0) {
              outlog(LOG_WARNING, "sv_nwpack2dgram(k=%d, a=%d): set additional-data: out of space", nwpack->kenner, nwpack->action);
              goto end_n2d;
            }
            break;
          }
          memcpy(dgram, nwpack->u.k_runconn.a_keys.s2c.data[istart].zdata, tlen);
          dgram += tlen; slen += tlen;
        }

        /* next keys-packet */
        pklen = slen;
        ianz--;
        istart++;
      }
      slen = pklen;
#ifdef NWPACK_DUMP
      { struct nwdata_packets nwp; cl_dgram2nwpack(remaddr, dgram0, slen, &nwp); }
#endif

    } else if (nwpack->action == NWDATA_ACTION_CONNECTED) {  /* server sends connected-client-info */
      /* set 1 byte: client-connection-bits */
      if (slen + 1 > NW_MAXPAKET) {
        outlog(LOG_WARNING, "sv_nwpack2dgram(k=%d, a=%d): set connected-client-info: out of space", nwpack->kenner, nwpack->action);
        goto end_n2d;
      }
      dgram[0] = nwpack->u.k_runconn.a_connected.s2c.conncl;
      dgram++; slen++;
#ifdef NWPACK_DUMP
      { struct nwdata_packets nwp; cl_dgram2nwpack(remaddr, dgram0, slen, &nwp); }
#endif

    } else if (nwpack->action == NWDATA_ACTION_XDATA_RECV) {  /* acknowledgement for client's sent exchange-data */
      /* set 2 bytes: sequence-number */
      if (slen + 2 > NW_MAXPAKET) {
        outlog(LOG_WARNING, "sv_nwpack2dgram(k=%d, a=%d): set sequence-number: out of space", nwpack->kenner, nwpack->action);
        goto end_n2d;
      }
      USHORT_GET(nwpack->u.k_runconn.a_xdata_recv.s2c.seqnr, dgram[0], dgram[1]);
      dgram += 2; slen += 2;
#ifdef NWPACK_DUMP
      { struct nwdata_packets nwp; cl_dgram2nwpack(remaddr, dgram0, slen, &nwp); }
#endif

    } else if (nwpack->action == NWDATA_ACTION_XDATA_SEND) {  /* send exchange-data */
      /* set 2 bytes: sequence-number */
      if (slen + 2 > NW_MAXPAKET) {
        outlog(LOG_WARNING, "sv_nwpack2dgram(k=%d, a=%d): set sequence-number: out of space", nwpack->kenner, nwpack->action);
        goto end_n2d;
      }
      USHORT_GET(nwpack->u.k_runconn.a_xdata_send.s2c.seqnr, dgram[0], dgram[1]);
      dgram += 2; slen += 2;

      /* set 2 bytes: length of exchange-data */
      if (slen + 2 > NW_MAXPAKET) {
        outlog(LOG_WARNING, "sv_nwpack2dgram(k=%d, a=%d): set exchange-data-length: out of space", nwpack->kenner, nwpack->action);
        goto end_n2d;
      }
      USHORT_GET(nwpack->u.k_runconn.a_xdata_send.s2c.xdatalen, dgram[0], dgram[1]);
      dgram += 2; slen += 2;

      /* set nwpack->u.k_runconn.a_xdata_send.s2c.xdatalen bytes: exchange-data */
      tlen = nwpack->u.k_runconn.a_xdata_send.s2c.xdatalen;
      if (tlen > 0) {
        if (slen + tlen > NW_MAXPAKET) {
          outlog(LOG_WARNING, "sv_nwpack2dgram(k=%d, a=%d): set exchange-data: out of space", nwpack->kenner, nwpack->action);
          goto end_n2d;
        }
        memcpy(dgram, nwpack->u.k_runconn.a_xdata_send.s2c.xdata, tlen);
        dgram += tlen; slen += tlen;
      }
#ifdef NWPACK_DUMP
      { struct nwdata_packets nwp; cl_dgram2nwpack(remaddr, dgram0, slen, &nwp); }
#endif

    } else {  /* unknown */
      outlog(LOG_WARNING, "sv_nwpack2dgram(k=%d): invalid action: %d", nwpack->kenner, nwpack->action);
      goto end_n2d;
    }

  } else {  /* unknown */
    outlog(LOG_WARNING, "sv_nwpack2dgram: invalid kenner: %d", nwpack->kenner);
    goto end_n2d;
  }

  return slen;

end_n2d:
  return 0;
} /* Ende sv_nwpack2dgram */
