diff options
| author | Sven Eisenhauer <sven@sven-eisenhauer.net> | 2023-11-10 15:11:48 +0100 |
|---|---|---|
| committer | Sven Eisenhauer <sven@sven-eisenhauer.net> | 2023-11-10 15:11:48 +0100 |
| commit | 33613a85afc4b1481367fbe92a17ee59c240250b (patch) | |
| tree | 670b842326116b376b505ec2263878912fca97e2 /Bachelor/Verteilte Systeme/Praktikum1 | |
| download | Studium-33613a85afc4b1481367fbe92a17ee59c240250b.tar.gz Studium-33613a85afc4b1481367fbe92a17ee59c240250b.tar.bz2 | |
Diffstat (limited to 'Bachelor/Verteilte Systeme/Praktikum1')
| -rw-r--r-- | Bachelor/Verteilte Systeme/Praktikum1/Makefile | 14 | ||||
| -rw-r--r-- | Bachelor/Verteilte Systeme/Praktikum1/README | 22 | ||||
| -rw-r--r-- | Bachelor/Verteilte Systeme/Praktikum1/error.cpp | 331 | ||||
| -rw-r--r-- | Bachelor/Verteilte Systeme/Praktikum1/inet.h | 19 | ||||
| -rw-r--r-- | Bachelor/Verteilte Systeme/Praktikum1/tcpcli.cpp | 129 | ||||
| -rw-r--r-- | Bachelor/Verteilte Systeme/Praktikum1/tcpserv.cpp | 226 | ||||
| -rw-r--r-- | Bachelor/Verteilte Systeme/Praktikum1/util.cpp | 86 |
7 files changed, 827 insertions, 0 deletions
diff --git a/Bachelor/Verteilte Systeme/Praktikum1/Makefile b/Bachelor/Verteilte Systeme/Praktikum1/Makefile new file mode 100644 index 0000000..2e568e8 --- /dev/null +++ b/Bachelor/Verteilte Systeme/Praktikum1/Makefile @@ -0,0 +1,14 @@ +all: tcpserv tcpcli
+
+tcpserv: tcpserv.o
+ g++ tcpserv.o -o tcpserv
+tcpcli: tcpcli.o
+ g++ tcpcli.o -o tcpcli
+
+tcpserv.o:
+ g++ -c -o tcpserv.o tcpserv.cpp
+tcpcli.o:
+ g++ -c -o tcpcli.o tcpcli.cpp
+
+clean:
+ rm -f *.o tcpserv tcpcli
diff --git a/Bachelor/Verteilte Systeme/Praktikum1/README b/Bachelor/Verteilte Systeme/Praktikum1/README new file mode 100644 index 0000000..74355c2 --- /dev/null +++ b/Bachelor/Verteilte Systeme/Praktikum1/README @@ -0,0 +1,22 @@ +1. Die Programme sind zu uebersetzen (auf Server und Client Rechner): + $ make tcpserv + g++ tcpserv.cpp -o tcpserv + $ + $ make tcpcli + g++ tcpcli.cpp -o tcpcli + $ + +2. Nun kann das Serverprogramm auf dem Server gestartet werden: + $ tcpserv $ + $ + +3. Auf jedem Clientrechner kann nun der Client gestartet werden. + $ tcpcli + Dies ist die erste Zeile + Dies ist die erste Zeile + 2. Nachricht + 2. Nachricht + Letzte Nachricht + Letzte Nachricht + ^D + $ diff --git a/Bachelor/Verteilte Systeme/Praktikum1/error.cpp b/Bachelor/Verteilte Systeme/Praktikum1/error.cpp new file mode 100644 index 0000000..5bf172d --- /dev/null +++ b/Bachelor/Verteilte Systeme/Praktikum1/error.cpp @@ -0,0 +1,331 @@ +/************************************************************************
+ * Error handling routines.
+ *
+ * The functions in this file are independent of any application
+ * variables, and may be used with any C program.
+ * Either of the names CLIENT or SERVER may be defined when compiling
+ * this function. If neither are defined, we assume CLIENT.
+ */
+
+//#include <varargs.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#include <iostream>
+using namespace std;
+
+#ifdef CLIENT
+#ifdef SERVER
+cant define both CLIENT and SERVER
+#endif
+#endif
+
+#ifndef CLIENT
+#ifndef SERVER
+#define CLIENT 1 /* default to client */
+
+#endif
+#endif
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+char *pname = NULL;
+
+#ifdef CLIENT /* these all output to stderr */
+
+ /* ------------------- BEGIN CLIENT ------------------- */
+
+/*
+ * Print the UNIX errno value.
+ */
+
+void my_perror()
+{
+ //char *sys_err_str();
+ char *str = strerror(errno);
+ cerr << str << endl;
+ //fprintf(stderr, " %s\n", sys_err_str());
+}
+/*
+ * Print the UNIX errno value.
+ * We just append it to the end of the emesgstr[] array.
+ */
+
+
+
+/*
+ * Fatal error. Print a message and terminate.
+ * Don't dump core and don't print the system's errno value.
+ *
+ * err_quit(str, arg1, arg2, ...)
+ *
+ * The string "str" must specify the conversion specification for any args.
+ */
+
+/*VARARGS1*/
+
+void err_quit(char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ if (pname != NULL)
+ cerr << pname;
+ fmt = va_arg(args, char *);
+ vfprintf(stderr, fmt, args);
+ fputc('\n', stderr);
+ va_end(args);
+
+ exit(1);
+}
+
+/*
+ * Fatal error related to a system call. Print a message and terminate.
+ * Don't dump core, but do print the system's errno value and its
+ * associated message.
+ *
+ * err_sys(str, arg1, arg2, ...)
+ *
+ * The string "str" must specify the conversion specification for any args.
+ */
+
+/*VARARGS1*/
+void err_sys(char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ if (pname != NULL) {
+ cerr << "if (pname != NULL) {" << endl;
+ fprintf(stderr, "%s: ", pname);
+
+ }
+ fmt = va_arg(args, char *);
+
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+
+ my_perror();
+
+ exit(1);
+}
+
+/*
+ * Recoverable error. Print a message, and return to caller.
+ *
+ * err_ret(str, arg1, arg2, ...)
+ *
+ * The string "str" must specify the conversion specification for any args.
+ */
+
+/*VARARGS1*/
+void err_ret(char *fmt, ...)
+{
+ va_list args;
+
+
+ va_start(args, fmt);
+ if (pname != NULL)
+ fprintf(stderr, "%s: ", pname);
+ fmt = va_arg(args, char *);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+
+ my_perror();
+
+ fflush(stdout);
+ fflush(stderr);
+
+ return;
+}
+
+/*
+ * Fatal error. Print a message, dump core (for debugging) and terminate.
+ *
+ * err_dump(str, arg1, arg2, ...)
+ *
+ * The string "str" must specify the conversion specification for any args.
+ */
+
+/*VARARGS1*/
+void err_dump(char *fmt, ...)
+{
+ va_list args;
+
+
+ va_start(args, fmt);
+ if (pname != NULL)
+ fprintf(stderr, "%s: ", pname);
+ fmt = va_arg(args, char *);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+
+ my_perror();
+
+ fflush(stdout); /* abort doesn't flush stdio buffers */
+ fflush(stderr);
+
+ abort(); /* dump core and terminate */
+ exit(1); /* shouldn't get here */
+}
+
+#endif /* ------------------- END CLIENT ------------------- */
+ /* ------------------- BEGIN SERVER ------------------- */
+#ifdef SERVER
+
+#ifdef BSD
+/*
+ * Under BSD, these server routines use the syslog(3) facility.
+ * They don't append a newline, for example.
+ */
+
+#include <syslog.h>
+
+#else /* not BSD */
+/*
+ * There really ought to be a better way to handle server logging
+ * under System V.
+ */
+
+#define syslog(a,b) cerr << "syslog: "<< (b)
+#define openlog(a,b,c) cerr << (a)
+
+#endif /* BSD */
+/*
+ * Print the UNIX errno value.
+ * We just append it to the end of the emesgstr[] array.
+ */
+
+char emesgstr[255] = {"test"}; /* used by all server routines */
+void my_perror()
+{
+
+ // register int len;
+ //char *sys_err_str();
+// len = strlen(emesgstr);
+ cerr << emesgstr
+ << strerror(errno)
+ << endl;
+ //sprintf(emesgstr + len, " %s", sys_err_str());
+}
+
+
+
+/*
+ * Identify ourself, for syslog() messages.
+ *
+ * LOG_PID is an option that says prepend each message with our pid.
+ * LOG_CONS is an option that says write to console if unable to send
+ * the message to syslogd.
+ * LOG_DAEMON is our facility.
+ */
+
+void err_init(char *ident)
+{
+ openlog(ident, (LOG_PID | LOG_CONS), LOG_DAEMON);
+}
+
+/*
+ * Fatal error. Print a message and terminate.
+ * Don't print the system's errno value.
+ *
+ * err_quit(str, arg1, arg2, ...)
+ *
+ * The string "str" must specify the conversion specification for any args.
+ */
+
+/*VARARGS1*/
+void err_quit(char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ fmt = va_arg(args, char *);
+ vsprintf(emesgstr, fmt, args);
+ va_end(args);
+
+ syslog(LOG_ERR, emesgstr);
+
+ exit(1);
+}
+
+/*
+ * Fatal error related to a system call. Print a message and terminate.
+ * Don't dump core, but do print the system's errno value and its
+ * associated message.
+ *
+ * err_sys(str, arg1, arg2, ...)
+ *
+ * The string "str" must specify the conversion specification for any args.
+ */
+
+/*VARARGS1*/
+void err_sys(char *fmt, ...)
+
+{
+ cerr << "err_sys: " << fmt << endl;
+ va_list args;
+ va_start(args, fmt);
+ fmt = va_arg(args, char *);
+ vsprintf(emesgstr, fmt, args);
+ va_end(args);
+
+ my_perror();
+ syslog(LOG_ERR, emesgstr);
+
+ exit(1);
+}
+
+/*
+ * Recoverable error. Print a message, and return to caller.
+ *
+ * err_ret(str, arg1, arg2, ...)
+ *
+ * The string "str" must specify the conversion specification for any args.
+ */
+
+/*VARARGS1*/
+void err_ret(char *fmt, ...)
+
+{
+ va_list args;
+
+ va_start(args, fmt);
+ fmt = va_arg(args, char *);
+ vsprintf(emesgstr, fmt, args);
+ va_end(args);
+
+ my_perror();
+ syslog(LOG_ERR, emesgstr);
+
+ return;
+}
+
+/*
+ * Fatal error. Print a message, dump core (for debugging) and terminate.
+ *
+ * err_dump(str, arg1, arg2, ...)
+ *
+ * The string "str" must specify the conversion specification for any args.
+ */
+
+/*VARARGS1*/
+void err_dump(char *fmt, ...)
+
+{
+ va_list args;
+ va_start(args,fmt);
+ fmt = va_arg(args, char *);
+ vsprintf(emesgstr, fmt, args);
+ va_end(args);
+
+ my_perror();
+ syslog(LOG_ERR, emesgstr);
+
+ abort(); /* dump core and terminate */
+ exit(1); /* shouldn't get here */
+}
+
+
+#endif /* ------------------- SERVER ------------------- */
diff --git a/Bachelor/Verteilte Systeme/Praktikum1/inet.h b/Bachelor/Verteilte Systeme/Praktikum1/inet.h new file mode 100644 index 0000000..6af7e71 --- /dev/null +++ b/Bachelor/Verteilte Systeme/Praktikum1/inet.h @@ -0,0 +1,19 @@ +/************************************************************************
+ * Definitions for TCP and UDP client/server programs.
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <asm/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+
+
+
+
+#define SERV_TCP_PORT 9018
+//#define SERV_HOST_ADDR "10.0.0.200" /* host addr for server */
+#define SERV_HOST_ADDR "127.0.0.1" /* Localhost */
diff --git a/Bachelor/Verteilte Systeme/Praktikum1/tcpcli.cpp b/Bachelor/Verteilte Systeme/Praktikum1/tcpcli.cpp new file mode 100644 index 0000000..ac10492 --- /dev/null +++ b/Bachelor/Verteilte Systeme/Praktikum1/tcpcli.cpp @@ -0,0 +1,129 @@ +/************************************************************************ + * + * Example of client using TCP protocol. + * + ***********************************************************************/ +#include <unistd.h> +#include "inet.h" +#include "error.cpp" +#include "util.cpp" +#include <iostream> +using namespace std; + +const int MAXLINE=255; // max length of a line + +// send message msg to server and receive response in resp +void mySend(int sockfd, char *msg, char *resp) { + + + int n; // Länge des Strings + // Daten senden + n = strlen(msg); + if (writen(sockfd, msg, n) != n) + err_sys("str_cli: writen error on socket"); // Fehler beim Schreiben + + // Daten empfangen + n = readline(sockfd, resp, MAXLINE); + if (n < 0) + err_dump("str_cli: readline error"); + resp[n] = 0; /* null terminate */ +} + + +void str_cli(FILE *fp, int sockfd) +{ + int n; + char sendline[MAXLINE], recvline[MAXLINE + 1]; + + + + // Auswahl der Optionen (Eintragen / Suchen) + int m_Auswahl = '0'; + + while (true) { + + cout<<"Telefonbuch\n\nBitte auswählen:\n"; + cout<<" 1: eintragen\n"; + cout<<" 2: suchen\n"; + cout<<" 3: beenden\n"; + cin>>m_Auswahl; + switch (m_Auswahl) { + case (1): + // Neuen Eintrag im Telefonbuch + cout<<"Eintragen:\n"; + char m_Name[50]; + char m_Tel[50]; + + cout<<"Name: "; scanf("%s", &m_Name); strcat(m_Name, "\n"); + cout<<"Tel: "; scanf("%s", &m_Tel); strcat(m_Tel, "\n"); + + mySend(sockfd, "addEntry\n", recvline); + if (strcmp(recvline,"OK\n") != 0) + printf("Error: %s\n", recvline); + mySend(sockfd, m_Name, recvline); + if (strcmp(recvline,"OK\n") != 0) + printf("Error: %s\n", recvline); + mySend(sockfd, m_Tel, recvline); + if (strcmp(recvline,"OK\n") != 0) + printf("Error: %s\n", recvline); + break; + case (2): + // Eintrag im Telefonbuch suchen + cout<<"Suchen\n"; + char m_Search[50]; + cout<<"Name: "; scanf("%s", &m_Search); strcat(m_Search, "\n"); + + mySend(sockfd, "searchEntry\n", recvline); + if (strcmp(recvline,"OK\n") != 0) + printf("Error: %s\n", recvline); + mySend(sockfd, m_Search, recvline); + printf("Ergebnis: %s\n", recvline); + + break; + case (3): + mySend(sockfd,"end\n",recvline); + cout<<"Client beendet...\n"; + return; + break; + default: + cout<<"Falsche Eingabe\n"; + break; + } + } + + +} +/***********************************************************************/ + +/************************************************************************ + * main function, client for TCP/IP echo server + */ +int main(int argc, char** argv) +{ + int sockfd; + struct sockaddr_in serv_addr; + + pname = argv[0]; + + // Fill in the structure "serv_addr" with the address of the + // server that we want to connect with. + bzero((char *) &serv_addr, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = inet_addr(SERV_HOST_ADDR); + serv_addr.sin_port = htons(SERV_TCP_PORT); + + // Open a TCP socket (an Internet stream socket). + if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + err_sys("client: can't open stream socket"); + + // Connect to the server. + if (connect(sockfd, (struct sockaddr *) &serv_addr, + sizeof(serv_addr)) < 0) + err_sys("client: can't connect to server"); + + str_cli(stdin, sockfd); /* do it all */ + + close(sockfd); + exit(0); +} +/***********************************************************************/ diff --git a/Bachelor/Verteilte Systeme/Praktikum1/tcpserv.cpp b/Bachelor/Verteilte Systeme/Praktikum1/tcpserv.cpp new file mode 100644 index 0000000..e23418e --- /dev/null +++ b/Bachelor/Verteilte Systeme/Praktikum1/tcpserv.cpp @@ -0,0 +1,226 @@ +static char rcsid[] = "$Id: tcpserv.c,v 1.1 2001/12/02 12:13:52 as Exp as $"; +/************************************************************************ + * + * Example of server using TCP protocol. + * + ***********************************************************************/ + +#include <unistd.h> +#include <sys/stat.h> // open() +#include "inet.h" +#include "error.cpp" +#include "util.cpp" +#include <iostream> + +#include <time.h> +#include <fstream> + +using namespace std; + +// Constant definitions +// +// maximum line length +const int MAXLINE=255; + +// structure for phone book records +struct telEintrag { // Einzelne Einträge im Telefonbuch + char name[50]; + char tel[50]; +}; + +// max. 50 records in a phone book +// global variables +// +// TODO: change to file or shared memory +// global variables are not good with fork() +// +telEintrag telBuch[50]; // 50 Einträge möglich +int telCount = 0; // Position des nächsten freien Platzes + +// write a line to socket sockfd +void myWrite(int sockfd, char *line) { + int n; + // send reply + n = strlen(line); + if (writen(sockfd, line, n) != n) { + err_dump("str_echo: writen error"); + } +} + +// read line from socket sockfd +void myRead(int sockfd, char *line) { + int n; + + + // receive data into line + n = readline(sockfd, line, MAXLINE); + + // error handling + if (n == 0) { + return; /* connection terminated */ + } + else if (n < 0) { + err_dump("str_echo: readline error"); + } + + + // console logging + + // time_t structure variable myTime + time_t myTime; + + // read time into myTime + time(&myTime); + + // char array for time conversion + char tmpTime[25]; + + // copy converted time into char array + strcpy(tmpTime, ctime(&myTime)); + + // append string terminating binary 0 + tmpTime[strlen(tmpTime)-1] = '\0'; + + // print time and received line to stdout + printf("[%s] Nachricht: %s",tmpTime,line); + +} + + +void str_echo(int sockfd) +{ + int n; + char line[MAXLINE]; + + + for ( ; ; ) { + // read line from socket + myRead(sockfd, line); + + // if "addEntry"-command was sent + if (strcmp(line, "addEntry\n") == 0) { + // send back "OK", we understood the command + myWrite(sockfd, "OK\n"); + + // now we receive the name + myRead(sockfd, line); + // name received + myWrite(sockfd, "OK\n"); + // save it in local memory + strcpy(telBuch[telCount].name, line); + + // now we receive the phone number + myRead(sockfd, line); + // number received + myWrite(sockfd, "OK\n"); + // save the number in local memory + strcpy(telBuch[telCount].tel, line); + // next time we fill the next array element + telCount++; + // we did it + printf("Neuer Eintrag im Telefonbuch.\n"); + + } else + // the "searchEntry"-command was sent + if (strcmp(line, "searchEntry\n") == 0) { + // send back "OK", we understood the command + myWrite(sockfd, "OK\n"); + + // receive the search string + myRead(sockfd, line); + // search the entry + int i=0; + bool found = false; + for (i; i < telCount; i++) { + + if (strcmp(telBuch[i].name, line) == 0) { + found = true; + // we found an entry + // send back the phone number + myWrite(sockfd, telBuch[i].tel); + } + } + // we did not find anything + if (found == false) + myWrite(sockfd, "Nicht gefunden.\n"); + + } else if (strcmp(line,"end\n")==0) + { + // client sent end command + // exiting... + myWrite(sockfd,"Server exiting... \n"); + exit(0); + } + else + { + // an undefined command was sent from client + myWrite(sockfd, "Command not found.\n"); + + } + + + } +} +/***********************************************************************/ + +/************************************************************************ + * main function, server for the TCP/IP echo server + */ +int main(int argc, char **argv) +{ + int sockfd, newsockfd, clilen, childpid; + // structures of socket addresses + struct sockaddr_in cli_addr, serv_addr; + pname = argv[0]; + + // Open a TCP socket (an Internet stream socket). + if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) + err_dump("server: can't open stream socket"); + + // Bind our local address so that the client can send to us. + + // make sure zeros are in serv_addr + bzero((char *) &serv_addr, sizeof(serv_addr)); + // now fill in information, which we need + serv_addr.sin_family = AF_INET; + // INADDR_ANY: System definiton -> accept connections on every interface + // htonl: convert byte order (host to network long) + serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); + // SERV_TCP_PORT defined in inet.h + // htons: convert byte order (host to network short) + serv_addr.sin_port = htons(SERV_TCP_PORT); + + // bind sockfd to socket address serv_addr (Server) + if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) + err_dump("server: can't bind local address"); + + // mark socket to accept connections + // limit 5 connections backlog in queue + listen(sockfd, 5); + + for ( ; ; ) { + // Wait for a connection from a client process. + // This is an example of a concurrent server. + + clilen = sizeof(cli_addr); + // make new socket for client connection and return + // the file descriptor of this socket + newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, + (socklen_t *) &clilen); + + if (newsockfd < 0) + err_dump("server: accept error"); + + if ( (childpid = fork()) < 0) + err_dump("server: fork error"); + + else if (childpid == 0) { // child process + printf("Verbinung aufgebaut.\n"); + close(sockfd); // close original socket + str_echo(newsockfd); // process the request + exit(0); + } + close(newsockfd); // parent process + } +} +/***********************************************************************/ diff --git a/Bachelor/Verteilte Systeme/Praktikum1/util.cpp b/Bachelor/Verteilte Systeme/Praktikum1/util.cpp new file mode 100644 index 0000000..88c8f66 --- /dev/null +++ b/Bachelor/Verteilte Systeme/Praktikum1/util.cpp @@ -0,0 +1,86 @@ +/************************************************************************
+ *
+ * Utility functions to use with sockets
+ *
+ ************************************************************************
+
+/************************************************************************
+ *
+ * Read "n" bytes from a descriptor.
+ * Use in place of read() when fd is a stream socket.
+ */
+#include <iostream>
+using namespace std;
+
+int readn(int fd, char* ptr, int nbytes)
+{
+ int nleft, nread;
+
+ nleft = nbytes;
+ while (nleft > 0) {
+ nread = read(fd, ptr, nleft);
+ if (nread < 0)
+ return(nread); /* error, return < 0 */
+ else if (nread == 0)
+ break; /* EOF */
+
+ nleft -= nread;
+ ptr += nread;
+ }
+ return(nbytes - nleft); /* return >= 0 */
+}
+/************************************************************************
+
+/************************************************************************
+ *
+ * Read a line from a descriptor. Read the line one byte at a time,
+ * looking for the newline. We store the newline in the buffer,
+ * then follow it with a null (the same as fgets(3)).
+ * We return the number of characters up to, but not including,
+ * the null (the same as strlen(3)).
+ */
+int readline(int fd,char* ptr, int maxlen)
+{
+ int n, rc;
+ char c;
+
+ for (n = 1; n < maxlen; n++) {
+ if ( (rc = read(fd, &c, 1)) == 1) {
+ *ptr++ = c;
+ if (c == '\n')
+ break;
+ } else if (rc == 0) {
+ if (n == 1)
+ return(0); /* EOF, no data read */
+ else
+ break; /* EOF, some data was read */
+ } else
+ return(-1); /* error */
+ }
+
+ *ptr = 0;
+ return(n);
+}
+/************************************************************************
+
+/************************************************************************
+ *
+ * Write "n" bytes to a descriptor.
+ * Use in place of write() when fd is a stream socket.
+ */
+int writen(int fd, char* ptr, int nbytes)
+{
+ int nleft, nwritten;
+
+ nleft = nbytes;
+ while (nleft > 0) {
+ nwritten = write(fd, ptr, nleft);
+ if (nwritten <= 0)
+ return(nwritten); /* error */
+
+ nleft -= nwritten;
+ ptr += nwritten;
+ }
+ return(nbytes - nleft);
+}
+/************************************************************************/
|
