summaryrefslogtreecommitdiffstats
path: root/Bachelor/Verteilte Systeme/Praktikum1
diff options
context:
space:
mode:
authorSven Eisenhauer <sven@sven-eisenhauer.net>2023-11-10 15:11:48 +0100
committerSven Eisenhauer <sven@sven-eisenhauer.net>2023-11-10 15:11:48 +0100
commit33613a85afc4b1481367fbe92a17ee59c240250b (patch)
tree670b842326116b376b505ec2263878912fca97e2 /Bachelor/Verteilte Systeme/Praktikum1
downloadStudium-master.tar.gz
Studium-master.tar.bz2
add new repoHEADmaster
Diffstat (limited to 'Bachelor/Verteilte Systeme/Praktikum1')
-rw-r--r--Bachelor/Verteilte Systeme/Praktikum1/Makefile14
-rw-r--r--Bachelor/Verteilte Systeme/Praktikum1/README22
-rw-r--r--Bachelor/Verteilte Systeme/Praktikum1/error.cpp331
-rw-r--r--Bachelor/Verteilte Systeme/Praktikum1/inet.h19
-rw-r--r--Bachelor/Verteilte Systeme/Praktikum1/tcpcli.cpp129
-rw-r--r--Bachelor/Verteilte Systeme/Praktikum1/tcpserv.cpp226
-rw-r--r--Bachelor/Verteilte Systeme/Praktikum1/util.cpp86
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);
+}
+/************************************************************************/