home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Developer CD v1.2
/
amidev_cd_12.iso
/
devcon
/
milan_1991
/
devcon91.2
/
network
/
socket
/
examples
/
server2.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-09-01
|
7KB
|
274 lines
/*
** server2.c
**
** Written by Dale Larson, Software Engineer, Commodore-Amiga, Inc.
** Copyright 1991, Commodore-Amiga, Inc.
** Permission to use granted provided this notice remains intact.
**
** This is a version of the ncopy server which processes multiple requests
** simultaneously. It spawns multiple processes to do so (it could also
** use selectwait() to do [see server3.c]). It is more complex than the
** simple server, but not much, and it is nicer under frequent and/or heavy
** use. It also allows users to copy a file from one location on a remote
** machine to another location on the same remote machine (i.e.
** "ncopy sprite!ram:x sprite!work:y"). A system requester will not
** pop up if the server recieves a request to read/write to/from a
** non-existent device.
**
** This server has no provision for exiting.
**
** You should be familiar with the ncopy client (ncopy.c and transfer.c) and
** the simple ncopy server (server1.c) before studying this server.
**
** Thanks to Randell Jessup for his idea on how to easily arbitrate access
** to the global Ns (which is used to pass info to child processes).
*/
#include "ncopy.h"
struct Library *SockBase;
#define MAXSOCKS 10
char vers[] = "\0$VER: server2 1.0 (25.02.91)";
void send_file(int s, BPTR file);
void get_file(int s, BPTR file);
void handle_request(void);
int init(void);
/* Not in SAS 5.10 or Manx 5.0d includes */
struct Process *CreateNewProcTags( unsigned long tag1type, ... );
/* global variable for New socket read by new processes: */
int Ns = 0;
/*
** main()
**
** Call init() then wait to accept connections. Once a connection has been
** accepted, start a new process to execute the handler function with the
** socket which accept() connected to a remote machine. Go back to accepting
** connections.
*/
main(int argc, char **argv)
{
int s; /* socket to accept connections on */
struct Process *pid;
s = init();
/*
** Accept connections from s and process them on ns.
*/
while(1)
{
/*
** Make sure that there is not a child process which hasn't
** had a chance to copy its socket. Ns must be initialized
** to zero before this while() and children must set Ns
** to zero when they have copied it.
*/
if(Ns)
{
Delay(1);
continue;
}
if( (Ns = accept(s,NULL,NULL)) >= 0 )
{
static char proc_name[20];
sprintf(proc_name, "ncopy server #%2d", Ns);
pid = CreateNewProcTags(NP_Entry, (LONG)handle_request,
NP_Name, (LONG)proc_name,
NP_WindowPtr, -1L,
TAG_DONE);
if(!pid)
{
s_close(Ns);
Ns = 0;
}
}
}
}
/*
** init()
**
** Get a socket, bind a name to it, express a willingness to accept
** connections to it (listen) and return the socket. Exit on error.
*/
int init(void)
{
struct sockaddr_in sin; /* socket address (internet) to establish */
int s, /* socket to accept connections on */
len = sizeof(sin);
/* Open Shared Socket library:
*/
if(SockBase = OpenLibrary( "inet:libs/socket.library", 0L ))
{
setup_sockets( MAXSOCKS, &errno );
}else
{
puts("Can't open socket.library.");
exit(RETURN_ERROR);
}
/*
** Initialize a socket.
*/
if( (s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("socket");
exit(RETURN_ERROR);
}
/*
** Bind name to socket.
** Since we got sin off the stack, it could contain anything, and so
** we zero it before initializing it.
*/
bzero(&sin, len);
sin.sin_family = AF_INET;
/*
** While prototyping a program, pick an unused port number above
** 1024 like I did here. For a real program, assign a name and a
** port number above 1024 and stick it in inet:db/servers on all
** machines which will use the application. That way the user can
** reconfigure port numbers used by new applications if necessary.
** You can modify the server to get the port number from the
** database by using code like this (instead of "sin.sin_port=
** htons(6666)" below):
**
** struct servent *servptr;
** char serv[] = "servicename";
**
** if( (servptr = getservbyname(serv, "tcp")) == NULL)
** {
** printf("Unknown service %s. Check inet:db/services.\n",serv);
** return RETURN_ERROR;
** }
** sin.sin_port = servptr->s_port;
*/
sin.sin_port = htons(6666);
sin.sin_addr.s_addr = INADDR_ANY;
if(bind(s, (struct sockaddr *)&sin, len) < 0)
{
perror("bind");
exit(RETURN_ERROR);
}
/*
** Put socket into "listen" state (ready to accept connections).
*/
listen(s,5);
return s;
}
/*
** handle_request()
**
** Handles a request to send or receive a file on a given socket.
** Handling a request consists of the following:
** 1) receive the mode (send or receive -- MODE_OLDFILE or MODE_NEWFILE)
** 2) receive the filename
** 3) attempt to open the file
** 4) return "\0" for succesful open,
** specially formated informative error message otherwise
** 5) call function to send or receive the file
** 6) closes the file we opened and the socket we were passed
*/
void handle_request(void)
{
int s; /* socket passed by parent */
char buffer[LENGTH];
int mode; /* AmigaDOS file open mode (MODE_OLDFILE or MODE_NEWFILE) */
BPTR file; /* BCPL pointer to an AmigaDOS file handle */
geta4();
s = Ns;
Ns = 0; /* So that parent may feel free to use it again */
/* Get the mode.
** Don't worry about making sure that we got what we wanted because we
** can't really screw anything up and we can't send an error message
** if our communcications are error-prone.
*/
recv(s, (char *)&mode, sizeof(int), 0);
/* Get the filename which we'll read or write (depending on mode).
** (Assume that we get only null-terminated strings.)
*/
recv(s, buffer, LENGTH, 0);
/*
** Attempt to open file.
*/
if( !(file = Open(buffer, mode)) )
{
int len;
len = strlen(buffer);
strncat(buffer, "': ", LENGTH-4); /* 4 not 3 'cause of nul */
Fault(IoErr(), NULL, buffer+len+3, LENGTH-len-4);
send(s, buffer, strlen(buffer)+1, 0);
s_close(s);
return;
}
/*
** Indicate succesful opening of file.
*/
send(s, "\0", 1, 0);
/*
** Send or recieve the file.
*/
if(mode == MODE_OLDFILE)
send_file(s, file);
else
get_file(s, file);
Close(file);
s_close(s);
}
void send_file(int s, BPTR file)
{
char buffer[LENGTH];
long actualLength;
do
{
actualLength = Read(file, (void *)buffer, LENGTH);
if(actualLength < 0)
return; /* Error, but we have no way to report it. */
if(send(s, buffer, actualLength, 0) < 0)
return; /* Error, but we have no way to report it. */
}while(actualLength);
}
void get_file(int s, BPTR file)
{
char buffer[LENGTH];
int n;
do
{
n = recv(s, buffer, LENGTH, 0);
if(n < 0)
return; /* Error, but we have no way to report it. */
if(Write(file, (void *)buffer, n) < 0)
return; /* Error, but we have no way to report it. */
}while(n);
}