home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Developer CD v1.2
/
amidev_cd_12.iso
/
devcon
/
milan_1991
/
devcon91.2
/
network
/
socket
/
examples
/
server3.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-09-01
|
7KB
|
248 lines
/*
** server3.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 utilizes selectwait() to do so (a server could also
** spawn multiple processes to do so). It is more complex than the simple
** server, but is nicer under frequent and/or heavy use, and 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"). Using
** selectwait() (or multiple processes) also makes it reasonable to implement
** exit-on-break-signal. A system requester will not pop up if the server
** recieves a request to read/write to/from a non-existent device.
**
** Note that this server really does not properly handle copying from one
** locations on a remote machine to another location on the same remote
** machine. It works fine for files not more than about 8k, but will hang
** for files larger than that. The reason is that it sends all of a file
** at once. If the target is another machine, the other machine's ncopy or
** server will read the data as this server writes it. But if this server
** is also supposed to read the data, 8 TCP packets will be buffered, then
** send() will block until some of them are read and acknowledged. This
** problem could be solved in the server by including a select() in the
** send loop, by not allowing ncopy to transfer to and from the same machine,
** or by redesigning the ncopy protocol. Any of these solutions would unduly
** complicate and excede the scope of this example. Note that the number '8'
** is an implementation-dependent number.
**
** You should be familiar with the ncopy client (ncopy.c and transfer.c) and
** the simple ncopy server (server1.c) before studying this server.
**
*/
#include "ncopy.h"
struct Library *SockBase;
#define MAXSOCKS 10
char vers[] = "\0$VER: server3 1.0 (28.02.91)";
int process(int s, int state, fd_set *mask, int highSock);
int nhs(int s, fd_set *mask);
int init(void);
/* state constants */
#define SCLOSE 0 /* Need to close the socket */
#define SINIT 1 /* Need to initialize connection */
#define SDATA 2 /* Need to recieve data and write to disk */
struct timeval NoTime = {0L, 0L};
main(int argc, char **argv)
{
int s, /* socket to accept connections on, new socket */
ns, /* new socket */
i, /* index in for loops */
state[FD_SETSIZE], /* where we are in communication on all socket */
highSock; /* the highest open socket */
fd_set sockmask, mask; /* mask of all open sockets, return val */
long umask;
highSock = s = init();
FD_ZERO(&sockmask);
FD_SET(s, &sockmask);
while(1)
{
mask = sockmask;
umask = SIGBREAKF_CTRL_C;
if(selectwait(highSock+1, &mask, NULL, NULL, NULL,
&umask) == -1)
{
perror("select");
goto cleanup;
}
for(i=0; i <= highSock; i++)
if(FD_ISSET(i, &mask))
if (i == s)
{
ns = accept(s, NULL, NULL);
if(ns != -1)
{
state[ns] = SINIT;
FD_SET(ns, &sockmask);
if(ns > highSock)
highSock = ns;
}
} else
{
state[i] = process(i, state[i], &sockmask, highSock);
if(state[i] == SCLOSE)
{
if(i == highSock)
highSock = nhs(i,&sockmask);
s_close(i);
FD_CLR(i, &sockmask);
}
}
}
cleanup:
for(i=0; i<=highSock; i++)
if( FD_ISSET(i, &sockmask) )
{
s_close(i);
}
cleanup_sockets();
CloseLibrary(SockBase);
}
int nhs(int s, fd_set *mask)
{
while(s--)
{
if(FD_ISSET(s, mask))
return s;
}
return FD_SETSIZE;
}
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);
}
if( (s = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket");
goto cleanup;;
}
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");
s_close(s);
goto cleanup;
}
listen(s,5);
return s;
cleanup:
cleanup_sockets();
CloseLibrary(SockBase);
exit(RETURN_ERROR);
}
int process(int s, int state, fd_set *mask, int highSock)
{
char buffer[LENGTH];
static int mode[FD_SETSIZE]; /* AmigaDOS file open modes */
static BPTR file[FD_SETSIZE]; /* File handles */
int n; /* number of bytes read/written */
switch(state)
{
case SINIT:
recv(s, (char *)&(mode[s]), sizeof(int), 0);
recv(s, buffer, LENGTH, 0);
if( !(file[s] = Open(buffer, mode[s])) )
{
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);
return SCLOSE;
}
send(s, "\0", 1, 0);
if(mode[s] == MODE_NEWFILE)
{
return SDATA;
}
/* fall through if MODE_OLDFILE */
case SDATA:
if(mode[s] == MODE_OLDFILE)
{
while(1)
{
n = Read(file[s], (void *)buffer, LENGTH);
if(n <= 0)
goto close;
if(send(s, buffer, n, 0) < 0)
goto close;
}
}else
{
n = recv(s, buffer, LENGTH, 0);
if(n <= 0)
goto close;
if(Write(file[s], (void *)buffer, n) < 0)
goto close;
return SDATA;
}
default:
;
/* in a real program, should do something more intellegent here */
}
close:
Close(file[s]);
return SCLOSE;
}