Makefile_bsd0100600000653700000360000000277507565020200012217 0ustar iankusers # # Make client_test and server_test programs # # if you're using the GNU compiler # CC = g++ CC = CC LD = $(CC) DEBUG = -g CFLAGS = -D_SOLARIS_ INCLUDE = LINK_FLAG = FLAGS = $(INCLUDE) $(DEBUG) $(CFLAGS) CLIENT_OBJ = client_test.o client.o SERVER_OBJ = server_test.o server.o COMMON_OBJ = cmdinfo.o neterr.o netio.o netwrap.o switch.o netcmd.o all: client_test server_test client_test: $(CLIENT_OBJ) $(COMMON_OBJ) ${LD} $(CLIENT_OBJ) $(COMMON_OBJ) -o $@ $(LINK_FLAG) server_test: $(SERVER_OBJ) $(COMMON_OBJ) ${LD} $(SERVER_OBJ) $(COMMON_OBJ) -o $@ $(LINK_FLAG) clean: rm -rf $(COMMON_OBJ) $(CLIENT_OBJ) $(SERVER_OBJ) client_test server_test cmdinfo.o: cmdinfo.C cmdinfo.h ${CC} -c $(FLAGS) cmdinfo.C neterr.o: neterr.C neterr.h ${CC} -c $(FLAGS) neterr.C netio.o: netio.C netio.h neterr.h ${CC} -c $(FLAGS) netio.C netwrap.o: netwrap.C neterr.h netwrap.h ${CC} -c $(FLAGS) netwrap.C switch.o: switch.C switch.h neterr.h netwrap.h ${CC} -c $(FLAGS) switch.C client.o: client.C client.h neterr.h netwrap.h switch.h \ cmdinfo.h connect.h ${CC} -c $(FLAGS) client.C server.o: server.C server.h neterr.h netwrap.h switch.h \ cmdinfo.h connect.h ${CC} -c $(FLAGS) server.C client_test.o: client_test.C neterr.h netwrap.h switch.h cmdinfo.h connect.h ${CC} -c $(FLAGS) client_test.C server_test.o: server_test.C neterr.h netwrap.h switch.h cmdinfo.h connect.h ${CC} -c $(FLAGS) server_test.C netcmd.o: netcmd.C netcmd.h cmdinfo.h netio.h neterr.h netinc.h $(CC) -c $(FLAGS) netcmd.C Makefile_nt0100600000653700000360000000356706726573044012111 0ustar iankusers # # Make client_test and server_test programs # CC = cl LD = $(CC) DEBUG = -Zi CFLAGS = -DWIN32 -Tp # # Path to MS VC++ include directory - only Microsoft would allow # the heresy of spaces in file names. # INCLUDE = -I "d:\Program Files\Microsoft Visual Studio\Vc98\include" LINK_FLAG = -link Wsock32.lib OBJSUF = obj EXE = .exe FLAGS = $(INCLUDE) $(DEBUG) $(CFLAGS) CLIENT_OBJ = client_test.$(OBJSUF) client.$(OBJSUF) SERVER_OBJ = server_test.$(OBJSUF) server.$(OBJSUF) COMMON_OBJ = cmdinfo.$(OBJSUF) neterr.$(OBJSUF) netio.$(OBJSUF) netwrap.$(OBJSUF) switch.$(OBJSUF) netcmd.$(OBJSUF) all: client_test$(EXE) server_test$(EXE) client_test$(EXE): $(CLIENT_OBJ) $(COMMON_OBJ) $(LD) $(CLIENT_OBJ) $(COMMON_OBJ) -o $@ $(LINK_FLAG) server_test$(EXE): $(SERVER_OBJ) $(COMMON_OBJ) $(LD) $(SERVER_OBJ) $(COMMON_OBJ) -o $@ $(LINK_FLAG) clean: rm -rf $(COMMON_OBJ) $(CLIENT_OBJ) $(SERVER_OBJ) client_test server_test cmdinfo.$(OBJSUF): cmdinfo.C cmdinfo.h $(CC) -c $(FLAGS) cmdinfo.C neterr.$(OBJSUF): neterr.C neterr.h $(CC) -c $(FLAGS) neterr.C netio.$(OBJSUF): netio.C netio.h neterr.h $(CC) -c $(FLAGS) netio.C netwrap.$(OBJSUF): netwrap.C neterr.h netwrap.h $(CC) -c $(FLAGS) netwrap.C switch.$(OBJSUF): switch.C switch.h neterr.h netwrap.h $(CC) -c $(FLAGS) switch.C client.$(OBJSUF): client.C client.h neterr.h netwrap.h switch.h \ cmdinfo.h connect.h $(CC) -c $(FLAGS) client.C server.$(OBJSUF): server.C server.h neterr.h netwrap.h switch.h \ cmdinfo.h connect.h $(CC) -c $(FLAGS) server.C client_test.$(OBJSUF): client_test.C neterr.h netwrap.h switch.h cmdinfo.h connect.h $(CC) -c $(FLAGS) client_test.C server_test.$(OBJSUF): server_test.C neterr.h netwrap.h switch.h cmdinfo.h connect.h $(CC) -c $(FLAGS) server_test.C netcmd.$(OBJSUF): netcmd.C netcmd.h cmdinfo.h netio.h neterr.h netinc.h $(CC) -c $(FLAGS) netcmd.C Makefile_solaris0100600000653700000360000000272506726573057013143 0ustar iankusers # # Make client_test and server_test programs # CC = CC LD = $(CC) DEBUG = -g CFLAGS = -D_SOLARIS_ INCLUDE = LINK_FLAG = -lxnet FLAGS = $(INCLUDE) $(DEBUG) $(CFLAGS) CLIENT_OBJ = client_test.o client.o SERVER_OBJ = server_test.o server.o COMMON_OBJ = cmdinfo.o neterr.o netio.o netwrap.o switch.o netcmd.o all: client_test server_test client_test: $(CLIENT_OBJ) $(COMMON_OBJ) ${LD} $(CLIENT_OBJ) $(COMMON_OBJ) -o $@ $(LINK_FLAG) server_test: $(SERVER_OBJ) $(COMMON_OBJ) ${LD} $(SERVER_OBJ) $(COMMON_OBJ) -o $@ $(LINK_FLAG) clean: rm -rf $(COMMON_OBJ) $(CLIENT_OBJ) $(SERVER_OBJ) client_test server_test cmdinfo.o: cmdinfo.C cmdinfo.h ${CC} -c $(FLAGS) cmdinfo.C neterr.o: neterr.C neterr.h ${CC} -c $(FLAGS) neterr.C netio.o: netio.C netio.h neterr.h ${CC} -c $(FLAGS) netio.C netwrap.o: netwrap.C neterr.h netwrap.h ${CC} -c $(FLAGS) netwrap.C switch.o: switch.C switch.h neterr.h netwrap.h ${CC} -c $(FLAGS) switch.C client.o: client.C client.h neterr.h netwrap.h switch.h \ cmdinfo.h connect.h ${CC} -c $(FLAGS) client.C server.o: server.C server.h neterr.h netwrap.h switch.h \ cmdinfo.h connect.h ${CC} -c $(FLAGS) server.C client_test.o: client_test.C neterr.h netwrap.h switch.h cmdinfo.h connect.h ${CC} -c $(FLAGS) client_test.C server_test.o: server_test.C neterr.h netwrap.h switch.h cmdinfo.h connect.h ${CC} -c $(FLAGS) server_test.C netcmd.o: netcmd.C netcmd.h cmdinfo.h netio.h neterr.h netinc.h $(CC) -c $(FLAGS) netcmd.C client.C0100600000653700000360000000136306726610364011317 0ustar iankusers #include "netinc.h" #include "cmdinfo.h" #include "neterr.h" #include "netio.h" #include "netcmd.h" #include "netwrap.h" #include "switch.h" #include "connect.h" #include "client.h" /* * client_init * */ Boolean cmd_client::client_init(const int port, const char *host_name ) { if (host_name != NULL) { connection cnx( port, host_name ); sockfd = cnx.client_connect(); } return (Boolean)(sockfd > 0); } // client_init /* * close * Send a close command to the server and close the socket To avoid leaving a port open, the server must close before the client. */ void cmd_client::client_close() { send_close( sockfd ); // send and acknowledge socket_close( sockfd ); // server should be closed at this point } client.h0100600000653700000360000000116606726610374011366 0ustar iankusers #ifndef _CLIENT_H_ #define _CLIENT_H_ class cmd_client : private netcmd { private: int sockfd; Boolean debug; public: cmd_client() { sockfd = 0; debug = TRUE; } Boolean client_init(const int port, const char *host_name); void send_struct( cmdinfo &data ) { send_info( sockfd, data ); } void recv_struct( cmdinfo &data ) { recv_info( sockfd, data ); } void send_command( COMMANDS cmd ) { send_cmd( sockfd, (unsigned int)cmd ); } COMMANDS recv_command() { return (COMMANDS)get_cmd( sockfd ); } void client_close(); Boolean debug_set() { return debug; } }; #endif client_test.C0100600000653700000360000000405506726573114012360 0ustar iankusers /* Test program for client. */ #include "netinc.h" #include "cmdinfo.h" #include "neterr.h" #include "netio.h" #include "netcmd.h" #include "client.h" void usage( const char *prog_name ) { printf("%s -help\n", prog_name); printf("%s [-p port] host_name | host_ip\n", prog_name ); printf("To connect to server use:\n"); printf(" %s \n", prog_name ); printf(" %s \n", prog_name ); printf("example: %s kremvax.com\n", prog_name ); printf("example: %s 192.168.66.6\n", prog_name ); printf("Default port = %d\n", CMD_PORT ); printf("To use another port use: -p \n"); printf("example: %s -p 1234 kremvax.com\n", prog_name ); } // usage Boolean process_args( int argc, char *argv[], int &port, char * &host_name ) { Boolean args_ok; args_ok = TRUE; port = 0; if (argc > 1 && argc < 4) { int arg_cnt; char *cur_arg; port = CMD_PORT; host_name = NULL; for (arg_cnt = 1; arg_cnt < argc; arg_cnt++) { cur_arg = argv[ arg_cnt ]; if (*cur_arg == '-') { cur_arg++; switch (*cur_arg) { case 'p': if (arg_cnt < argc - 1) { arg_cnt++; port = atoi(argv[ arg_cnt ]); } else { usage( argv[ 0 ] ); args_ok = FALSE; } break; case 'h': default: usage( argv[0] ); args_ok = FALSE; break; } // switch } else { // argument is the host name host_name = cur_arg; } } // for } // if else { usage( argv[0] ); args_ok = FALSE; } return args_ok; } // process_args main(int argc, char *argv[]) { int port; char *host_name; if (process_args( argc, argv, port, host_name)) { cmd_client client; // open socket if (client.client_init(port, host_name)) { cmdinfo info; // initializes to {bad_command, 0} client.send_command( start_sending ); while (info.cmd != send_done) { client.recv_struct( info ); info.pr(); if (info.cmd != send_done) { client.send_command( send_next ); } } client.client_close(); } // if } } // main cmdinfo.C0100600000653700000360000000203406726573317011462 0ustar iankusers #include "netinc.h" #include "cmdinfo.h" const char *cmdinfo::get_command_str(void) { const char *str; str = "bad command"; switch ( cmd ) { case twas: str = "twas"; break; case brillig: str = "brillig"; break; case and: str = "and"; break; case the: str = "the"; break; case slithey: str = "slithey"; break; case tothes: str = "tothes"; break; case did: str = "did"; break; case gyre: str = "gyre"; break; case gimble: str = "gimble"; break; case in: str = "in"; break; case wabe: str = "wabe"; break; case all: str = "all"; break; case mimsy: str = "mimsy"; break; case were: str = "were"; break; case borogroves: str = "borogroves"; break; case moonraths: str = "moonraths"; break; case outgrabe: str = "outgrabe"; break; case send_done: str = "send_done"; break; } // end switch return str; } void cmdinfo::pr() { printf("command = %s, data = 0x%08x\n", get_command_str(), data ); } cmdinfo.h0100600000653700000360000000127106726573327011532 0ustar iankusers #ifndef _CMDINFO_H_ #define _CMDINFO_H_ #define CMD_PORT 2010 typedef enum { bad_command = 0, twas, brillig, and, the, slithey, tothes, did, gyre, gimble, in, wabe, all, mimsy, were, borogroves, moonraths, outgrabe, send_done, cmd_close_socket, start_sending, send_next, sending_data, acknowledge, ascii_mode, last_command } COMMANDS; #define com_succ( cmd ) ((COMMANDS)((int)cmd + 1)) class cmdinfo { private: const char *get_command_str(void); public: COMMANDS cmd; unsigned int data; public: cmdinfo() { cmd = bad_command; data = 0; } void pr(); }; #endif connect.h0100600000653700000360000000212306726610357011534 0ustar iankusers #ifndef _CONNECT_H_ #define _CONNECT_H_ /* The author of this software is Ian Kaplan www.bearcave.com iank@bearcave.com Copyright (c) Ian Kaplan, 1999 See "copyright" file for allowed use. */ /* * connection * Connect the client and server on a fixed port at a fixed IP. The port and IP are initialized as part of the object constructor. */ class connection { private: typedef enum { HOST_NAME_MAX = 127 } bogus; const size_t port; switchboard pannel; char host_name[ HOST_NAME_MAX+1 ]; public: connection( const size_t p, const char *h_name ) : port(p) { int i; assert( host_name != NULL ); for (i = 0; i < HOST_NAME_MAX && h_name[i] != '\0'; i++) { host_name[i] = h_name[i]; } host_name[i] = '\0'; } // connection int client_connect() { int sockfd; sockfd = pannel.client_connect( port, host_name ); if (sockfd > 0) { pannel.connect_message(); } return sockfd; } int server_accept() { int sockfd; sockfd = pannel.server_accept( port ); return sockfd; } }; #endif copyright0100600000653700000360000000256306726610667011701 0ustar iankusers /* The author of this software is Ian Kaplan www.bearcave.com iank@bearcave.com Copyright (c) Ian Kaplan, 1999 THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED WARRANTY. IN PARTICULAR, THE AUTHOR MAKES NO REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. This is not public-domain software or shareware, and it is not protected by a `copyleft' agreement, like the code from the Free Software Foundation. This is available free for your personal research and instructional use under the `fair use' provisions of the copyright law. You may, however, redistribute this in whole or in part provided you acknowledge its source and author, Ian Kaplan. You must also include this copyright notice (copyright file) in your distribution. You may, for example, include the distribution in a CDROM of free software, provided you charge only for the media, or mirror the distribution files at your Web site. You may not sell this or any product derived from it in which it is a significant part of the value of the product. Any use where others stand to make a profit from what is primarily my work, requires a license agreement. Per-copy and unlimited use licenses are available; for more information, contact Ian Kaplan, iank@bearcave.com */netcmd.C0100600000653700000360000000523006726573336011317 0ustar iankusers #include "netinc.h" #include "neterr.h" #include "cmdinfo.h" #include "netio.h" #include "cmdinfo.h" #include "netcmd.h" void netcmd::send_close( int sockfd ) { unsigned int ack_command = cmd_close_socket; if (is_debug_mode()) printf("send_close\n"); Writen( sockfd, (char *)&ack_command, sizeof( ack_command ) ); } // SendAck void netcmd::recv_close( int sockfd ) { unsigned int close_command; if (is_debug_mode()) printf("recv_close\n"); close_command = get_cmd( sockfd ); if (close_command != cmd_close_socket) printf("recv_close: bad close value\n"); } // recv_close int netcmd::Close( int fd ) { int close_rslt; #ifdef WIN32 close_rslt = closesocket( fd ); #else close_rslt = close( fd ); #endif return close_rslt; } // Close /* * socket_close * */ void netcmd::socket_close( int sockfd ) { int close_rslt; if (is_debug_mode()) printf("close\n"); if (sockfd > 0) { close_rslt = Close( sockfd ); if (close_rslt != 0) { printf("socket_close: close error. errno = %d\n", errno ); } } else printf("socket_close: attempt to close null socket\n"); } // socket_close /* * get_cmd * */ unsigned int netcmd::get_cmd( int sockfd ) { char buf[1024]; int amt_read; unsigned int cmd; if (is_debug_mode()) printf("get_cmd\n"); cmd = 0; amt_read = read_block( sockfd, buf, sizeof(buf) ); if (amt_read == sizeof(cmd)) { memcpy(&cmd, buf, sizeof(cmd)); } else { int i; printf("get_cmd: wrong amount of data read - amt_read = %d\n", amt_read ); for (i = 0; i < amt_read && i < sizeof(buf); i++) { if ((i % sizeof(int)) == 0) printf(" 0x"); printf("%02x", (unsigned char)buf[i]); } printf("\n"); } return cmd; } // get_cmd void netcmd::send_cmd( int sockfd, unsigned int cmd ) { Writen( sockfd, (char *)&cmd, sizeof( cmd ) ); } // send_cmd void netcmd::send_info( int sockfd, cmdinfo &data ) { if (is_debug_mode()) printf("send_info\n"); Writen( sockfd, (void *)&data, sizeof( data ) ); } // send_info void netcmd::recv_info( int sockfd, cmdinfo &data ) { char buf[1024]; int amt_read; if (is_debug_mode()) printf("recv_info\n"); amt_read = read_block( sockfd, buf, sizeof(buf) ); if (amt_read == 0) { Error( "recv_info - socket terminated prematurely" ); } else if (amt_read == sizeof(data)) { memcpy(&data, buf, sizeof(data)); } else printf("recv_info: wrong amount of data read\n"); } // recv_info void netcmd::SendAck( int sockfd ) { unsigned int ack_command = acknowledge; if (is_debug_mode()) printf("SendAck\n"); send_cmd( sockfd, ack_command ); } // SendAck netcmd.h0100600000653700000360000000103106726573341011353 0ustar iankusers #ifndef _NETCMD_H_ #define _NETCMD_H_ /* * class netcmd * Support for sending and receiving client and server commands. Derived from the netio class. */ class netcmd : protected netio { public: void send_close( int fd ); void recv_close( int fd ); void socket_close( int fd ); unsigned int get_cmd( int fd ); void send_cmd(int fd, unsigned int cmd ); void send_info( int sockfd, cmdinfo &data ); void recv_info( int sockfd, cmdinfo &data ); void SendAck( int sockfd ); int Close( int sockfd ); }; #endif neterr.C0100600000653700000360000000363706726573352011353 0ustar iankusers /* Bear Transfer Protocol (BTP), a TCP/IP socket based file transfer utility The author of this software is Ian Kaplan www.bearcave.com iank@bearcave.com Copyright (c) Ian Kaplan, 1999 See "copyright" file for allowed use. */ #include "netinc.h" #include "neterr.h" /* * PrintErr * Print an error message, but don't exit */ void neterr::PrintErr( char *msg ) { if (msg != NULL) { fprintf(stderr, "%s", msg ); } #ifdef WIN32 fprintf(stderr, " %d, %s", WSAGetLastError(), strerror(WSAGetLastError()) ); #else fprintf(stderr, " %s", strerror( errno ) ); #endif fprintf(stderr, "\n"); } // PrintErr /* * Error * Report a serious error and exit the program with the status -1. */ void neterr::Error(char *msg) { PrintErr( msg ); #ifdef WIN32 WSACleanup(); #endif exit( -1 ); } /* Error */ /* * get_errno * System independent (UNIX or Win32) function to get the error number. */ int neterr::get_errno() { int err_ret; #ifdef WIN32 err_ret = WSAGetLastError(); #else err_ret = errno; #endif return err_ret; } /* get_errno */ /* Determine whether or not the error result is EINTR/WSAEINTR. This indicates that the socket read (recv) operation has been interruped and should be retried. The Dark Lord knows whether this actually works under Win32. Definition for: WSAEINTR (win32) EINTR (unix) Interrupted function call. An asynchronous signal (such as SIGINT or SIGQUIT) was caught by the process during the execution of an interruptible function. If the signal handler performs a normal return, the interrupted function call will seem to have returned the error condition. */ int neterr::is_EINTR( int err_rslt ) { int rslt; rslt = 0; if (err_rslt != 0) { #ifdef WIN32 rslt = (err_rslt == WSAEINTR); #else rslt = (err_rslt == EINTR); #endif } return rslt; } /* is_EINTR */ neterr.h0100600000653700000360000000074006726573357011415 0ustar iankusers #ifndef _NETERR_H_ #define _NETERR_H_ /* Bear Transfer Protocol (BTP), a TCP/IP socket based file transfer utility The author of this software is Ian Kaplan www.bearcave.com iank@bearcave.com Copyright (c) Ian Kaplan, 1999 See "copyright" file for allowed use. */ /* * neterr * Error reporting and recovery */ class neterr { public: void PrintErr( char *msg ); void Error(char *msg); int get_errno(); int is_EINTR( int err_rslt ); }; #endif netinc.h0100600000653700000360000000155106726573363011374 0ustar iankusers #ifndef _NETINC_H_ #define _NETINC_H_ #ifdef WIN32 /* * WIN32 */ #define WIN32_LEAN_AND_MEAN #include #include // for getcwd on win32 #else /* * UNIX */ #include #include #include #include #include #include #include typedef int SOCKET; #define SOCKET_ERROR -1 #define INVALID_SOCKET -1 #define closesocket close #endif #include #include #include #include #include #include #include #include #define forever while(1) #define DEFAULT_PORT 5001 #define DEFAULT_PROTO SOCK_STREAM // TCP #define BACKLOG 5 #ifdef FALSE #undef FALSE #endif #ifdef TRUE #undef TRUE #endif typedef enum { FALSE = 0, TRUE = 1, BogusFiller } Boolean; #endif netio.C0100600000653700000360000002045006726573370011162 0ustar iankusers /* Bear Transfer Protocol (BTP), a TCP/IP socket based file transfer utility The author of this software is Ian Kaplan www.bearcave.com iank@bearcave.com Copyright (c) Ian Kaplan, 1999 See "copyright" file for allowed use. */ #include "netinc.h" #include "neterr.h" #include "cmdinfo.h" #include "netio.h" /* A Note on "Endian-ness" Our histories of six thousand moons make no mention of any other regions, than the two great empires of Lilliput and Blefuscu. These two mighty powers have, as I was going to tell you, been engaged in a most obstinate war for six and thirty moons past. It began upon the following occasion. It is allowed on all hands, that the primative way of breaking eggs before we eat them, was upon the larger end: but his present Majesty's grandfather, while he was a boy, going to eat an egg, and breaking it according to the ancient practice, happened to cut one of his fingers. Whereupon the emperor his father, published an edict, commanding his subjects, upon great penalty, to break the smaller end of their eggs. [...] It is computed, that eleven thousand persons have, at several times, suffered death, rather than submit to break their eggs at the smaller end. Gulliver's Travels, Jonathan Swift On a "little endian" machine a pointer to a word of memory points to the least significant byte. On a "big endian" machine a pointer to a word of memory points to the most significant byte. The iNTEL x86 family is little endian. The SPARC and powerPC are big endian. The server and the client may be running on systems with different endian-ness. This matters when sending word size values, including COMMANDS and data sizes. If the platforms the client and server are running on differ in endian-ness, the word values are converted when they are read. */ /* * client_endian_check * Pass the 32-bit value 0x00000001 to the server. The server will pass back its version of 0x00000001. If the values don't match then there is an endian mismatch between the client and the server. As a result, the bytes must be flipped (see byte_flip, below) in each word passed between the systems. Note that this function assumes that both the client and the server are running on 32-bit machines or at least that the software was compiled for 32-bit mode. */ void netio::client_endian_check(int fd) { // buffer for data from server size_t data_in[ DATA_BUF_SIZE/sizeof(size_t) ]; int amt_read; size_t word_out = 0x00000001; Writen( fd, &word_out, sizeof( word_out ) ); data_in[0] = 0; if ((amt_read = read_block( fd, (char *)data_in, sizeof( data_in ))) == 0) { Error("client_endian_check: server terminated prematurely"); } else { if (amt_read == sizeof( word_out )) { if (data_in[0] != 0) { if (word_out != data_in[0]) { // There is an endian mismatch between the client // and the server. mismatch = TRUE; } } else { Error("client_endian_check: no data returned from server"); } } } } // client_endian_check /* * server_endian_check * Send 0x00000001 to the client so that the client can determine its endianness. */ void netio::server_endian_check(int fd ) { // buffer for data from client size_t data_in[ DATA_BUF_SIZE/sizeof(size_t) ]; int amt_read; data_in[0] = 0; if ((amt_read = read_block( fd, (char *)data_in, sizeof( data_in ))) == 0) { Error("server_endian_check: error on read"); } else { if (amt_read == sizeof( size_t )) { if (data_in[0] != 0) { if (data_in[0] != 0x00000001 ) { // There is an endian mismatch between the client // and the server. mismatch = TRUE; } } else { Error("server_endian_check: no data sent by client"); } } } // Send the client 0x00000001 size_t word_out = 0x00000001; Writen( fd, &word_out, sizeof( word_out ) ); } // server_endian_check /* * byte_flip * Convert from one "endian-ness" to another "endian-ness" This function is passed an unsigned word in one format (little endian) and it returns it in another format (big endian). */ unsigned int netio::byte_flip( const unsigned int little ) { typedef union { unsigned char bytes[ 4 ]; unsigned int u; } TRIX; TRIX big; unsigned char t; big.u = little; t = big.bytes[3]; big.bytes[3] = big.bytes[0]; big.bytes[0] = t; t = big.bytes[1]; big.bytes[1] = big.bytes[2]; big.bytes[2] = t; return big.u; } // byte_flip /* * writen * Write "n" bytes from the buffer pointed to by vptr to the file descriptor fd. */ int netio::writen(int fd, const void *vptr, size_t n) { const int FLAGS = 0; size_t nleft; int nwritten; const char *ptr; int err_rslt; ptr = (char *)vptr; nleft = n; while (nleft > 0) { if ( (nwritten = send(fd, ptr, nleft, FLAGS )) <= 0) { err_rslt = get_errno(); if (is_EINTR( err_rslt )) { /* send was canceled by an external signal, try again */ printf("writen: is_EINTR is TRUE - send was canceled\n"); nwritten = 0; } else return(-1); /* error */ } nleft -= nwritten; ptr += nwritten; } return(n); } /* end writen */ /* * get_block * Read a block of data from the socket fd. */ int netio::read_block(int fd, char *pBlock, unsigned int block_size ) { const int FLAGS = 0; int cnt = 0; do { cnt = recv(fd, pBlock, block_size, FLAGS); } while (cnt < 0 && is_EINTR( get_errno()) ); return( cnt ); } /* read_block */ /* * Writen * Write N bytes, pointed to by ptr, to the socket descriptor "fd" */ void netio::Writen(int fd, void *ptr, size_t nbytes) { if (writen(fd, ptr, nbytes) != nbytes) Error("writen error"); } // writen /* * send_io_block * Send an io_block data structure. */ void netio::send_io_block( int sockfd, io_block &blk, int num_bytes) { if (debug) { printf("send_io_block: data size = %d, total sent = %d\n", num_bytes, num_bytes + IO_BUF_EXTRA ); } // Note that the command and size are not sent byte flipped if there // is an endian mismatch. The protocol is that the reader // always puts the data in the right form. blk.com = sending_data; blk.size = num_bytes; // send data block Writen(sockfd, (void *)&blk, num_bytes + IO_BUF_EXTRA); } // send_io_block /* * RecvCommand * Get a command response from the remote system */ COMMANDS netio::RecvCommand( int sockfd, const char *prog_name ) { char message_in[ DATA_BUF_SIZE ]; neterr err; COMMANDS com; char *pWordBytes; int num_read, i; if ((num_read = read_block( sockfd, message_in, sizeof( message_in))) == 0) { char buf[128]; sprintf(buf, "%s: RecvCommand - server terminated prematurely", prog_name ); Error( buf ); } if (num_read != sizeof( com )) printf("RecvCommand: num_read = %d\n", num_read ); pWordBytes = (char *)&com; // If there is no mismatch between the endian-ness, the // data can simply be copied across if (! endian_mismatch()) { for (i = 0; i < sizeof(com); i++) { pWordBytes[i] = message_in[ i ]; } } else { // There is an endian mismatch, so flip bytes for (i = 0; i < sizeof(com); i++) { pWordBytes[(sizeof(com)-1) - i] = message_in[ i ]; } } return com; } // RecvCommand /* * GetAck * */ void netio::GetAck( int sockfd, COMMANDS com, const char *prog_name ) { const int MAXBUF = 256; char buf[ MAXBUF ]; COMMANDS com_in; neterr err; if ((com_in = RecvCommand( sockfd, prog_name )) != acknowledge) { sprintf(buf, "%s: GetAck failed for command = %d", prog_name, com ); err.Error( buf ); } } // GetAck /* * SendCommand * Send a command to the remote system */ void netio::SendCommand(int sockfd, COMMANDS com ) { Writen( sockfd, (char *)&com, sizeof( com ) ); } // SendCommand /* * print_mode * Print the transfer mode (e.g., ascii or binary) */ void netio::print_mode(void) { COMMANDS cmd; cmd = get_mode(); if (cmd == ascii_mode) printf("ascii"); else printf("binary"); } // print_mode /* Initialize static variables that are shared by all instances of the netio class. */ Boolean netio::mismatch = FALSE; COMMANDS netio::mode = ascii_mode; netio.h0100600000653700000360000000506406726573376011241 0ustar iankusers #ifndef _NETIO_H_ #define _NETIO_H_ /* Bear Transfer Protocol (BTP), a TCP/IP socket based file transfer utility The author of this software is Ian Kaplan www.bearcave.com iank@bearcave.com Copyright (c) Ian Kaplan, 1999 See "copyright" file for allowed use. */ /* netio class The netio class is the base class for TCP I/O and for file I/O. The class contains two static variables which will be shared by all instances of the class: mismatch: This variable is true if there is an "endian" mismatch between the client and the server. mode This variable will be either ascii_mode or binary_mode. On a UNIX to UNIX transfer, this variable will have no effect, since binary mode is ignored on UNIX systems. On a transfer between a UNIX system and an NT system, binary mode stops translation of Windows CR NL sequences into a NL. Binary mode must be used for the transfer of tar files and other binary data. These variables are initialized in globals.C as: Boolean netio::mismatch = FALSE; COMMANDS netio::mode = ascii_mode; */ #define Kilo 1024 #define IO_BUF_EXTRA (sizeof(COMMANDS) + sizeof(int)) #define IO_BUF_SIZE (8 * Kilo) - IO_BUF_EXTRA typedef struct { COMMANDS com; unsigned int size; char buf[ IO_BUF_SIZE ]; } io_block; class netio : protected neterr { private: static Boolean mismatch; // "endian" mismatch between client and server static COMMANDS mode; // ascii_mode (default) or binary_mode private: Boolean debug; private: int get_char(int fd, char *pCh ); int readline(int fd, void *vptr, size_t maxlen); protected: typedef enum { DATA_BUF_SIZE = 1024 } bogosity; unsigned int byte_flip( const unsigned int little ); public: netio() { debug = FALSE; } int writen(int fd, const void *vptr, size_t n); int read_block(int fd, char *pBlock, unsigned int block_size ); void Writen(int fd, void *ptr, size_t nbytes); void send_io_block( int sockfd, io_block &blk, int num_bytes); void SendCommand(int sockfd, COMMANDS com ); void GetAck( int sockfd, COMMANDS com, const char *prog_name ); COMMANDS RecvCommand( int sockfd, const char *prog_name ); void client_endian_check(int sockfd ); void server_endian_check( int sockfd ); Boolean endian_mismatch(void) { return mismatch; } COMMANDS get_mode(void) { return mode; } void set_mode( COMMANDS m ) { mode = m; } void print_mode(void); void set_debug() { debug = TRUE; } void clear_debug() { debug = FALSE; } Boolean is_debug_mode() { return debug; } }; // netio #endif netwrap.C0100600000653700000360000000337607565017556011535 0ustar iankusers /* Bear Transfer Protocol (BTP), a TCP/IP socket based file transfer utility The author of this software is Ian Kaplan www.bearcave.com iank@bearcave.com Copyright (c) Ian Kaplan, 1999 See "copyright" file for allowed use. */ #include "netinc.h" #include "neterr.h" #include "netwrap.h" /* * Socket * */ SOCKET netwrap::Socket(int family, int type, int protocol) { SOCKET conn_socket; conn_socket = socket(family, type, protocol ); /* Open a socket */ if (conn_socket < 0 ) { Error("Server: Error Opening socket: Error"); } return conn_socket; } // Socket void netwrap::Bind( SOCKET listen_socket, struct sockaddr *pSockAddr, int data_size) { // // bind() associates a local address and port combination with the // socket just created. This is most useful when the application is a // server that has a well-known port that clients know about in advance. // if (bind(listen_socket, pSockAddr, data_size ) == SOCKET_ERROR) { Error( "bind() failed with error" ); } } // Bind void netwrap::Listen( SOCKET listen_socket, int backlog ) { if (listen(listen_socket, backlog) == SOCKET_ERROR) { Error( "listen() failed with error" ); } } // Listen SOCKET netwrap::Accept( SOCKET listen_socket, struct sockaddr *pFrom, socklen_t *pFrom_size ) { SOCKET msgsock; msgsock = accept(listen_socket, pFrom, pFrom_size ); if (msgsock == INVALID_SOCKET) { Error( "accept() error"); } return msgsock; } // Accept /* * Connect * */ void netwrap::Connect( SOCKET conn_socket, struct sockaddr *pServer, size_t data_size ) { assert( pServer != NULL ); if (connect(conn_socket, pServer, data_size ) == SOCKET_ERROR) { Error("connect() failed"); } } // Connect netwrap.h0100600000653700000360000000147207565017501011563 0ustar iankusers #ifndef _NETWRAP_H_ #define _NETWRAP_H_ /* Bear Transfer Protocol (BTP), a TCP/IP socket based file transfer utility The author of this software is Ian Kaplan www.bearcave.com iank@bearcave.com Copyright (c) Ian Kaplan, 1999 See "copyright" file for allowed use. */ /* * netwrap * This class contains wrapper functions for the various network intrinsic functions. */ class netwrap : private neterr { public: SOCKET Socket(int family, int type, int protocol); void Bind( SOCKET listen_socket, struct sockaddr *pSockAddr, int data_size); void Listen( SOCKET listen_socket, int backlog ); void Connect( SOCKET conn_socket, struct sockaddr *pServer, size_t data_size ); SOCKET Accept( SOCKET listen_socket, struct sockaddr *pFrom, socklen_t *pFrom_size ); }; // netwrap #endif server.C0100600000653700000360000000213206726573414011346 0ustar iankusers #include "netinc.h" #include "cmdinfo.h" #include "neterr.h" #include "netwrap.h" #include "netio.h" #include "netcmd.h" #include "switch.h" #include "connect.h" #include "server.h" Boolean cmd_server::server_init() { const char *dummy_ip = "0.0.0.0"; connection cnx( port, dummy_ip ); sockfd = cnx.server_accept(); char buf[128]; struct hostent *pHostent; if (gethostname(buf, sizeof(buf)) == 0) { printf("Server is connected to client\n"); printf("Server is running on %s\n", buf ); pHostent = gethostbyname( buf ); if (pHostent != NULL) { int i; char *pCh; pCh = pHostent->h_addr; printf("Server IP is "); for (i = 0; i < pHostent->h_length; i++) { printf("%u", (unsigned char)pCh[i]); if (i < pHostent->h_length-1) printf("."); } printf("\n"); } else { printf("server_init: gethostbyname failed\n"); } } else { printf("server_init: failed to get hostname\n"); } return (Boolean)(sockfd > 0); } // server_init void cmd_server::server_close() { recv_close( sockfd ); socket_close( sockfd ); } server.h0100600000653700000360000000104606726573410011412 0ustar iankusers #ifndef _SERVER_H_ #define _SERVER_H_ class cmd_server : private netcmd { private: int sockfd; int port; public: cmd_server( int p) : port( p ) { sockfd = 0; } Boolean server_init(); void send_struct( cmdinfo &data ) { send_info( sockfd, data ); } void recv_struct( cmdinfo &data ) { recv_info( sockfd, data ); } void send_command( COMMANDS cmd ) { send_cmd( sockfd, (unsigned int)cmd ); } COMMANDS recv_command() { return (COMMANDS)get_cmd( sockfd ); } void server_close(); }; #endif server_test.C0100600000653700000360000000332606726573423012413 0ustar iankusers #include "netinc.h" #include "cmdinfo.h" #include "neterr.h" #include "netio.h" #include "netcmd.h" #include "server.h" void usage( const char *prog_name ) { printf("%s -help\n", prog_name); printf("%s [-p port]\n", prog_name ); printf("Default port = %d\n", CMD_PORT ); printf("To use another port use: -p \n"); printf("example: %s -p 1234\n", prog_name ); } // usage Boolean process_args( int argc, char *argv[], int &port ) { Boolean args_ok; args_ok = TRUE; port = 0; if (argc == 1 || argc == 3) { char *cur_arg; port = CMD_PORT; if (argc == 3) { if (strcmp(argv[1], "-p") == 0) { port = atoi(argv[ 2 ]); } else { usage( argv[0]); args_ok = FALSE; } } } // if else { usage( argv[0] ); args_ok = FALSE; } return args_ok; } // process_args /* Test program for server */ main(int argc, char *argv[]) { int port; if (process_args( argc, argv, port)) { cmd_server server( port ); cmdinfo info; COMMANDS com; int cnt; cnt = 1; if (server.server_init()) { COMMANDS start_cmd, ack_cmd; start_cmd = server.recv_command(); if (start_cmd == start_sending) { for (com = twas; com < send_done; com = com_succ( com )) { info.cmd = com; info.data = cnt; server.send_struct( info ); ack_cmd = server.recv_command(); if (ack_cmd != send_next) { printf("%s: expected start_next command, got 0x%x\n", argv[0], start_cmd ); } cnt++; } // for info.cmd = send_done; info.data = 0; server.send_struct( info ); server.server_close(); } else { printf("%s: expected start command, got 0x%x\n", argv[0], start_cmd ); } } // if } } // main switch.C0100600000653700000360000001230507565017657011350 0ustar iankusers /* Bear Transfer Protocol (BTP), a TCP/IP socket based file transfer utility The author of this software is Ian Kaplan www.bearcave.com iank@bearcave.com Copyright (c) Ian Kaplan, 1999 See "copyright" file for allowed use. */ #include "netinc.h" #include "neterr.h" #include "netwrap.h" #include "cmdinfo.h" #include "netio.h" #include "switch.h" /* * WinInit * WinSock initialization. */ void switchboard::WinInit(void) { #if WIN32 WSADATA wsaData; if (WSAStartup(0x202,&wsaData) == SOCKET_ERROR) { fprintf(stderr,"WSAStartup failed with error %d\n", WSAGetLastError()); WSACleanup(); exit( -1 ); } #endif } // WinInit /* * is_ip * This function returns TRUE if the the string argument is in the form num.num.num.num. Otherwise the function returns false. */ Boolean switchboard::is_ip( const char *host_name ) { Boolean rslt = TRUE; if (host_name != NULL) { int len; int i; len = strlen( host_name ); for (i = 0; i < len; i++) { if (host_name[i] != '.' && (! isdigit( host_name[i] ))) { rslt = FALSE; break; } } } else { rslt = FALSE; } return rslt; } // is_ip /* * addr_to_ip_str * This function is passed a hostent structure. It conversts the address in the hostent structure to an IP string (e.g., www.xxx.yyy.zzz) and places the result in the ip_addr. */ void switchboard::addr_to_ip_str( struct hostent *pHostent, char *ip_addr, size_t ip_addr_size ) { if (pHostent != NULL) { char *tmp_ip; char *pCh; int ip_len; // ip_len in bytes int i; memset( ip_addr, 0, ip_addr_size ); pCh = pHostent->h_addr; tmp_ip = ip_addr; ip_len = pHostent->h_length; for (i = 0; i < ip_len && tmp_ip < ip_addr + sizeof(ip_addr); i++) { sprintf(tmp_ip, "%u", (unsigned char)pCh[i]); tmp_ip = tmp_ip + strlen(tmp_ip); if (i < ip_len-1 && tmp_ip < ip_addr + sizeof(ip_addr)) { *tmp_ip = '.'; tmp_ip++; } } // for if (debug_set()) { printf("addr_to_ip_str: ip = %s\n", ip_addr ); } } } // addr_to_ip_str /* * get_hostent * */ struct hostent *switchboard::get_hostent( const char *server_name ) { struct hostent *hp; neterr err; // // Attempt to detect if we should call gethostbyname() or // gethostbyaddr() if (! is_ip(server_name)) { /* server address is a name */ hp = gethostbyname(server_name); } else { /* Convert nnn.nnn address to a usable one */ unsigned int addr; addr = inet_addr(server_name); hp = gethostbyaddr((char *)&addr,4,AF_INET); } if (hp == NULL ) { char buf[128]; sprintf(buf, "Client: Cannot resolve address [%s]:", server_name); err.Error( buf ); } return hp; } // get_hostent /* * print_inet_addr * Print an IP address in "dot format" (e.g., 192.125.34.27). The function is passed a pointer to an array of bytes, where each byte contains one part of the IP address. */ void switchboard::print_inet_addr( struct hostent *pHstent ) { char buf[64]; addr_to_ip_str( pHstent, buf, sizeof(buf) ); printf("\n"); } // print_inet_addr /* * connect_message * Print a connect message */ void switchboard::connect_message(void) { if (pHostent != NULL) { printf("Connected to %s at ", pHostent->h_name ); print_inet_addr( pHostent ); } else { printf("connect_message: pHostent is NULL\n"); } } // connect_message /* * set_sockaddr * Initialize the sockaddr_in data structure */ void switchboard::set_sockaddr( struct sockaddr_in *pSockAddr, int family, unsigned int port ) { memset( pSockAddr, 0, sizeof(struct sockaddr_in) ); pSockAddr->sin_family = AF_INET; pSockAddr->sin_addr.s_addr = htonl(INADDR_ANY); pSockAddr->sin_port = htons(port); } // set_sockaddr /* * server_accept * Listen on "port". Errors will terminate the program. The function returns the socket file descriptor (fd) that results from accepting a connection from the client. */ int switchboard::server_accept( const unsigned int port ) { int listenfd, connfd; socklen_t clilen; struct sockaddr_in servaddr, cliaddr; netwrap netfunc; WinInit(); listenfd = Socket( AF_INET, SOCK_STREAM, 0); set_sockaddr( &servaddr, AF_INET, port ); Bind( listenfd, (struct sockaddr*)&servaddr, sizeof( servaddr) ); Listen( listenfd, BACKLOG ); clilen = sizeof( cliaddr ); connfd = netfunc.Accept( listenfd, (struct sockaddr*)&cliaddr, &clilen); return connfd; } // server_accept /* * client_connect * Connect to the server on the system "sys_name", using "port". The function returns the socket file descriptor (fd). */ int switchboard::client_connect( const unsigned int port, const char *sys_name ) { int sockfd; struct sockaddr_in servaddr; WinInit(); memset( &servaddr, 0, sizeof( servaddr )); sockfd = Socket( AF_INET, SOCK_STREAM, 0); set_sockaddr( &servaddr, AF_INET, port ); pHostent = get_hostent( sys_name ); // copy the four byte IP address from the hostent data structure // to the sin_addr field. memcpy(&servaddr.sin_addr, pHostent->h_addr, pHostent->h_length ); Connect( sockfd, (struct sockaddr *)&servaddr, sizeof( servaddr ) ); return sockfd; } // client_connect switch.h0100600000653700000360000000243206726610352011402 0ustar iankusers #ifndef _SWITCH_H_ #define _SWITCH_H_ /* Bear Transfer Protocol (BTP), a TCP/IP socket based file transfer utility The author of this software is Ian Kaplan www.bearcave.com iank@bearcave.com Copyright (c) Ian Kaplan, 1999 See "copyright" file for allowed use. */ /* The UNIX networking model is a bit like the old telephone system with patch cables and connection sockets. This class provides the server "accept" function, along with the client "connect" function. */ class switchboard : private netwrap { private: struct hostent *pHostent; // hostent for currect connection Boolean debug; private: void WinInit(void); Boolean is_ip( const char *host_name ); struct hostent *get_hostent( const char *server_name ); void set_sockaddr( struct sockaddr_in *pSockAddr, int family, unsigned int port ); void addr_to_ip_str( struct hostent *pHostent, char *ip_addr, size_t ip_addr_size ); void print_inet_addr( struct hostent *pHstent ); Boolean debug_set() { return debug; } public: switchboard() { pHostent = NULL; debug = TRUE; } int server_accept( const unsigned int port ); int client_connect( const unsigned int port, const char *sys_name ); void connect_message(void); }; // switchboard #endif