Revision 4e5d304eb7cd5589b924ffb8b423b6f15511b35d authored by Ron Burkey on 20 October 2018, 17:47:00 UTC, committed by Ron Burkey on 20 October 2018, 17:47:00 UTC
the recently-added documents about YUL, was transcribed. Because the original program contained a deliberate error in YUL (as well as some constructs that have unintentionally become errors in yaYUL), I've provided it in two forms: TRIVIUM (which matches the original scan, to the extent feasible) and TRIVIUM-repaired (which has the deliberate and unintentional errors fixed, but otherwise retains the identical functionality of the original).
1 parent c6c292e
enetHost.c
/*
* This program was formed basically by just cutting and pasting
* from the enet tutorial (http://enet.bespin.org/Tutorial.html)
* and then adding a thread for keyboard input, so I guess it should
* have the same license as the tutorial has ... which isn't specified.
* The enet library itself has the following license, so let's suppose
* that it's the license that applies:
*
* Copyright (c) 2002-2011 Lee Salzman
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom
* the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Filename: enetHostTest.c
* Purpose: Provides a test for the socket interface used to
* connect Gemini OBC emulation programs like yaOBC,
* yaPanel, etc. It can act either as a client (for
* connecting to yaOBC) or a server (for connecting
* to yaPanel et al.). Once running, it simply sends
* any strings typed at the keyboard to the server
* (if it's a client) or to all connected clients
* (if it's a server). Conversely, it prints any
* strings it receives from connected sockets.
* Reference: http://www.ibiblio.org/apollo/Gemini.html#Protocol
* History: 2012-01-14 RSB Wrote.
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
#include <enet/enet.h>
#define PORT 19653
#define PROMPT "enet> "
static int Port = PORT;
// Should really protect the variable "peer" with a mutex,
// since in theory there would be a brief interval after a
// disconnect in which the variable might still be non-NULL
// even though the disconnect had already occurred, and
// therefore KeyboardThreadFunction() might be tricked into
// using it, possibly crashing the program.
static volatile ENetPeer *peer = NULL;
static int IsServer = 0; // 1 for server, 0 for client.
static ENetHost *host;
// Function for the keyboard thread.
void *
KeyboardThreadFunction(void *Data)
{
int i;
char Input[81] = "hello", *s;
ENetPacket *packet;
fprintf(stderr, "Ctrl-C to exit.\n");
while (1)
{
fprintf(stderr, PROMPT);
if (NULL == fgets(Input, sizeof(Input), stdin))
continue;
if (!IsServer && peer == NULL)
{
fprintf(stderr, "Not connected to server.\n");
continue;
}
// Trim off trailing CR or LF.
for (s = Input; *s; s++)
if (*s == '\n' || *s == '\r')
{
*s = 0;
break;
}
packet = enet_packet_create(Input, strlen(Input) + 1,
ENET_PACKET_FLAG_RELIABLE);
if (IsServer)
enet_host_broadcast(host, 0, packet);
else
{
i = enet_peer_send((ENetPeer *) peer, 0, packet);
if (i)
fprintf(stderr, "Failed.\n");
else
fprintf(stderr, "Succeeded.\n");
}
enet_host_flush(host);
}
}
int
main(int argc, char **argv)
{
int i, j, RetVal = 1;
pthread_t KeyboardThread;
// Parse the command-line arguments.
for (i = 1; i < argc; i++)
{
if (!strcmp(argv[i], "--client"))
IsServer = 0;
else if (!strcmp(argv[i], "--server"))
IsServer = 1;
else if (1 == sscanf (argv[i], "--port=%d", &j))
Port = j;
else
{
fprintf(stderr, "USAGE:\n");
fprintf(stderr, " enetHostTest [OPTIONS]\n");
fprintf(stderr, "The allowed OPTIONS are:\n");
fprintf(stderr, "--help Display this help-info.\n");
fprintf(stderr, "--server Start a server.\n");
fprintf(stderr, "--client Start a client (the default).\n");
fprintf(stderr, "--port=P Defaults to --port=%d.\n", PORT);
return (1);
}
}
// Initialize the socket library.
if (enet_initialize() != 0)
{
fprintf(stderr, "An error occurred while initializing ENet.\n");
return EXIT_FAILURE;
}
atexit(enet_deinitialize);
//---------------------------------------------------------------------------
// Set up the host as either a client or a server. In either
// case, the variable "host" will be used as a pointer to the host.
if (IsServer)
{
ENetAddress address;
ENetHost *server;
fprintf(stderr, "Starting up enet server.\n");
/* Bind the server to the default localhost. */
/* A specific host address can be specified by */
/* enet_address_set_host (& address, "x.x.x.x"); */
address.host = ENET_HOST_ANY;
/* Bind the server to port. */
address.port = Port;
server = enet_host_create(&address, 32, 1, 0, 0);
if (server == NULL)
{
fprintf(stderr,
"An error occurred while trying to create an ENet server host.\n");
exit(EXIT_FAILURE);
}
host = server;
}
else // !IsServer, so must be a client.
{
ENetHost *client;
fprintf(stderr, "Starting up enet client.\n");
client = enet_host_create(NULL, 1, 2, 0, 0);
if (client == NULL)
{
fprintf(stderr,
"An error occurred while trying to create an ENet client host.\n");
exit(EXIT_FAILURE);
}
host = client;
}
//---------------------------------------------------------------------------
// Start up another thread to get keyboard commands, so as to be able to
// initiate messages over the socket connection.
i = pthread_create(&KeyboardThread, NULL, KeyboardThreadFunction, NULL);
if (i != 0)
{
fprintf(stderr, "Keyboard thread creation failed with code %d.\n", i);
goto Done;
}
//---------------------------------------------------------------------------
// Infinite loop to service the host.
while (1)
{
ENetEvent event;
ENetAddress address;
// Connect to the server, if necessary.
if (!IsServer && peer == NULL)
{
enet_address_set_host(&address, "localhost");
address.port = Port;
peer = enet_host_connect(host, &address, 2, 0);
if (peer == NULL)
{
fprintf(stderr, "\rConnection failed.\n" PROMPT);
#ifdef WIN32
Sleep (100);
#else
usleep(100 * 1000);
#endif
}
}
// Service the host for incoming packets, connects, disconnects.
enet_host_service(host, &event, 1000);
switch (event.type)
{
case ENET_EVENT_TYPE_CONNECT:
fprintf(stderr, "\rA new client connected from 0x%08X:%u.\n" PROMPT,
event.peer -> address.host, event.peer -> address.port);
/* Store any relevant client information here. */
event.peer -> data = "Client information";
break;
case ENET_EVENT_TYPE_RECEIVE:
fprintf (stderr, "\r");
printf(
"%u 0x%08X:%u \"%s\"\n",
event.packet -> dataLength,
event.peer -> address.host, event.peer -> address.port,
event.packet -> data);
fflush(stdout);
fprintf (stderr, PROMPT);
/* Clean up the packet now that we're done using it. */
enet_packet_destroy(event.packet);
break;
case ENET_EVENT_TYPE_DISCONNECT:
fprintf(stderr, "\r0x%08X:%u disconnected.\n" PROMPT,
event.peer -> address.host, event.peer -> address.port);
/* Reset the peer's client information. */
event.peer -> data = NULL;
if (!IsServer)
peer = NULL;
break;
default:
//printf ("No events.\n");
break;
}
}
RetVal = 0;
Done: ;
enet_host_destroy(host);
return (RetVal);
}
Computing file changes ...