SAI ||
Sommersemester 1997 ||
Systemnahe Software II ||
Übungen
<- Alle Module
Lösung zu Blatt 5 (Aufgabe 6): gbmesg.h + gbmesg.c
Kommunikation zwischen Klienten und Server (Klientenseite).
/*
* gbmesg.h - headerfile for Gobang C/S communication
*
* Martin Hasch, University of Ulm, June 1997
*/
#include <unistd.h>
/*
* Request codes.
*/
#define RQ_SIGNOFF 0
#define RQ_SIGNON_BLACK 1
#define RQ_SIGNON_WHITE 2
#define RQ_SIGNON_KIBITZ 3
#define RQ_MOVE 4
#define RQ_RESIGN 8
#define RQ_KILL 15
/*
* Message codes.
*/
#define MSG_DRAW 0
#define MSG_BLACK_WINS 1
#define MSG_WHITE_WINS 2
#define MSG_ABORT 3
#define MSG_TOGGLE_EMPTY 4
#define MSG_TOGGLE_BLACK 5
#define MSG_TOGGLE_WHITE 6
#define MSG_SIZE 7
#define MSG_YOUR_TURN 8
#define MSG_ILLEGAL_MOVE 9
typedef struct {
unsigned m_code;
unsigned m_x;
unsigned m_y;
} Message;
/*
* Create and try to open the communication channel to a server.
* Result is 1 on success, otherwise 0.
*/
int mesg_init(pid_t server);
/*
* Close the communication channel.
* Automatically called on exit.
*/
void mesg_cleanup(void);
/*
* Send a request. Result is 1 on success, otherwise zero.
*/
int mesg_sendrequest(unsigned code, unsigned x, unsigned y);
/*
* Wait for and receive a message. Result is 1 one success, otherwise 0.
* (message) must point to an allocated message buffer.
*/
int mesg_receive(Message *message);
/*
* gbmesg.c - Gobang C/S communication
*
* Martin Hasch, University of Ulm, June 1997
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "gbmesg.h"
#define SERVER_FIFO "/tmp/gbs.%05d"
#define CLIENT_FIFO "/tmp/gbc.%05d"
#define FIFO_NAMELEN 16
typedef unsigned long Request;
typedef unsigned short Msg;
static Request rqTemplate = 0L; /* "constant" part of a request */
static int outputfd = -1; /* fd of fifo we are writing to */
static int inputfd = -1; /* fd of fifo we a reading from */
static char my_fifo[FIFO_NAMELEN]; /* node name of input fifo */
static int should_unlink = 0; /* should my_fifo be unlinked? */
/*
* Map a request code and parameters to a request.
*/
#define packrq(c, x, y) ((Request) (rqTemplate | \
((c) & 0xf) << 12 | ((x) & 0x3f) << 6 | ((y) & 0x3f)))
/*
* Send a request. Result is 1 on success, otherwise zero.
*/
int mesg_sendrequest(unsigned code, unsigned x, unsigned y)
{
Request request;
request = packrq(code, x, y);
return write(outputfd, &request, sizeof request) == sizeof request;
}
/*
* Simple signal handling routine (for SysV):
* Re-installs itself and is done.
*/
static void simple_handler(int sig)
{
(void) signal(sig, simple_handler);
}
/*
* Signal handler to unlink my_fifo and die.
*/
static void unlink_handler(int sig)
{
(void) unlink(my_fifo);
(void) kill(getpid(), sig);
}
/*
* Signal handler for interrupt key. Triggers signoff and exit.
*/
static void intr_handler(int sig)
{
if ( outputfd >= 0 )
(void) mesg_sendrequest(RQ_SIGNOFF, 0, 0);
exit(-1);
}
/*
* Close the communication channel.
* Automatically called on exit.
*/
void mesg_cleanup(void)
{
if ( inputfd >= 0 )
(void) close(inputfd), inputfd= -1;
if ( outputfd >= 0 )
(void) close(outputfd), outputfd= -1;
if ( should_unlink )
(void) unlink(my_fifo), should_unlink = 0;
}
/*
* If (enable != 0), prepare for my_pipe to be unlinked on termination;
* otherwise undo these preparations.
*
* Note that old-style signal handling like this yields race conditions.
* For a safer approach one might want to use sigset(), sighold() etc.
*/
static void prepare_unlinking(int enable)
{
void (* sigaction)(int);
int sig;
if ( enable ) {
should_unlink = 1;
for ( sig=SIGHUP; sig<=SIGTERM; ++sig )
if ( sig != SIGKILL && (sigaction = signal(sig,
unlink_handler)) != SIG_DFL )
(void) signal(sig, sigaction);
} else {
should_unlink = 0;
for ( sig=SIGHUP; sig<=SIGTERM; ++sig )
if ( sig != SIGKILL && (sigaction = signal(sig,
SIG_DFL)) != unlink_handler )
(void) signal(sig, sigaction);
}
}
/*
* Create and try to open the communication channel to a server.
* Result is 1 on success, otherwise 0.
*/
int mesg_init(pid_t server)
{
char server_fifo[FIFO_NAMELEN];
rqTemplate = (Request) getpid() << 16;
(void) sprintf(server_fifo, SERVER_FIFO, (int) server);
(void) sprintf(my_fifo, CLIENT_FIFO, (int) getpid());
(void) signal(SIGPIPE, simple_handler);
(void) signal(SIGINT, intr_handler);
if ( !should_unlink ) {
if ( mknod(my_fifo, S_IFIFO|0622, 0L) ) {
perror(my_fifo);
return 0;
}
prepare_unlinking(/*enable*/ 1);
}
if ( atexit(mesg_cleanup) ) {
perror("atexit");
mesg_cleanup();
return 0;
}
if ( chmod(my_fifo, 0622) ) {
perror(my_fifo);
return 0;
}
if ( (outputfd = open(server_fifo, O_WRONLY)) < 0 ) {
perror(server_fifo);
return 0;
}
/*
* In order not to block when we open our newly created fifo
* we open it in no-delay mode. This is immediately turned off,
* however, since it seems okay to block later on on writing.
*/
if ( (inputfd = open(my_fifo, O_RDONLY|O_NDELAY)) < 0 ) {
perror(my_fifo);
(void) close(outputfd), outputfd = -1;
return 0;
}
if ( fcntl(inputfd, F_SETFL, fcntl(inputfd, F_GETFL) & ~O_NDELAY) ) {
perror(my_fifo);
(void) close(inputfd), inputfd = -1;
(void) close(outputfd), outputfd = -1;
return 0;
}
return 1;
}
/*
* Wait for and receive a message. Result is 1 one success, otherwise 0.
* (message) must point to an allocated message buffer.
*/
int mesg_receive(Message *message)
{
Msg rawmsg;
size_t bytes;
do {
bytes = read(inputfd, &rawmsg, sizeof rawmsg);
if ( bytes < 0 )
return 0;
} while ( bytes < sizeof rawmsg ); /* ignore rubbish */
message->m_code = rawmsg >> 12 & 0xf;
message->m_x = (rawmsg >> 6) & 0x3f;
message->m_y = rawmsg & 0x3f;
/*
* We want to get rid of the node associated with our fifo as soon
* as possible (i.e. once the server has plugged in), so that the
* named pipe becomes anonymous, bound to die with the associated
* processes. When the first message has arrived it is therefore
* time to say good-bye... The signal handler cleaning up the
* fifo on premature termination hereby becomes obsolete, too.
*/
if ( should_unlink ) {
(void) unlink(my_fifo);
should_unlink = 0;
prepare_unlinking(/*disable*/ 0);
}
return 1;
}
<- Alle Module
SAI ||
Sommersemester 1997 ||
Systemnahe Software II ||
Übungen
Martin Hasch, Juni 1997