#include #include #include #include #include #include #include #define MAX_THREADS 10 #define GOODBYE 0 #ifndef TCP_NODELAY #define TCP_NODELAY 1 #endif typedef struct s_theadInfo //for thread { pthread_t *threads; int idx; int sockfd; } threadInfo; /* prototypes */ void * serve(void *arg); // Thread-Funktion void sig_break(int signo); // Signal-Handler /* globals */ int nThreads; char dbgstatus[MAX_THREADS]; int sockfd; int DM_ANZ; /* MAIN */ int main( int argc, char *argv[] ) { struct sockaddr_in server; struct sockaddr_in their_addr; int sin_size; int length; int msgsock; int rval; pthread_t threadid; pthread_t threads[MAX_THREADS]; threadInfo *ti; int idx; int sockoption; if ( argc < 2 ) { printf("Aufruf -> dmserver Port\n"); exit (-1); } #ifdef TEST_FEHLER printf("Serverversion mit Fehler \n"); #else printf("Serverversion ohne Fehler \n"); #endif dbgstatus[MAX_THREADS] = 0; nThreads = 0; bzero(threads, sizeof(threads)); sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { printf("Unable to open stream socket\n"); exit(-1); } /* CTRL-C Handler einhaengen */ signal(SIGINT, sig_break); // signal(SIGPIPE, sig_pipe); // Name socket using wildcards server.sin_family = AF_INET; // TCP/IP server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons(atoi(argv[1])); sockoption = 1; if (setsockopt (sockfd, IPPROTO_TCP, TCP_NODELAY, (char *) &sockoption, sizeof(sockoption)) != 0) { printf("Failed to set socket option TCP_NODELAY\n"); exit (1); } // Dem Socket wird eine Port-Nummer zugewiesen if (bind(sockfd, (struct sockaddr *)&server, sizeof(server))) { printf("Unable to bind stream socket\n"); exit(-1); } // name length = sizeof(server); if (getsockname(sockfd, (struct sockaddr *)&server, &length)) { printf("Unable to get socket name\n"); exit(-1); } printf("Socket has port #%d\n", ntohs(server.sin_port)); // Start accepting connections listen(sockfd, 1); for (;;) { sin_size = sizeof(struct sockaddr_in); msgsock = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size ); /* anyone connected */ if (msgsock < 0) printf("Unable to accept message\n"); else { printf("server: connection from %s\n", inet_ntoa(their_addr.sin_addr)); if (nThreads >= MAX_THREADS) { printf("MaxThreads reached\n"); continue; } // Durch ti werden dem Thread alle Infos uebergeben ti = (threadInfo *)malloc(sizeof(threadInfo)); if (!ti) { printf ("Memory\n"); exit(-1); } // Freie Stelle in der Tabelle suchen: idx = 0; while (threads[idx] && idx < MAX_THREADS) ++idx; // Folgendes braucht unser Thread: ti->threads = threads; // Tabelle mit allen Thread-IDs ti->idx = idx; // Seine stelle in dieser Tabelle ti->sockfd = msgsock; // Socket-Handle fuer seine Connection if (pthread_create(&threadid, NULL, &serve, (void *)ti)) { free(ti); printf("Thread could not be started\n"); continue; } threads[idx] = threadid; // Thread-ID in die Tabelle einfuegen ++nThreads; } /* end else Connected */ } /* end for ever */ } /* Thread for serving clients */ void * serve(void *arg) // wird pro Connection aufgerufen { int rval = 0; // Return-Wert char buf[128]; char sbuf[128]; char *sbufzgr = sbuf; threadInfo *ti = (threadInfo *)arg; // Zeiger auf ThreadInfo von main-Thread int len, nbytes, len2read; // Diverse Zaehler int templen; pthread_detach(pthread_self()); // Thread wird mit der Funktion beendet dbgstatus[ti->idx] = '0'; while (1) { int nleft,nread; char *ptr ; dbgstatus[ti->idx] = '1'; /* 1. command recv a)length of command at first b)command 2. send answer a)lenght of answer b)answer */ /* receive the command */ /* 1a receive length */ #ifdef TEST_FEHLER nbytes = spbsRecvn(ti->sockfd, (char *)&len, sizeof(int)); dbgstatus[ti->idx] = '-'; if ( nbytes < 0 ) { printf("Laenge fehlerhaft empfangen\n"); exit(1); } if (nbytes != sizeof(int)) { printf("Laenge nicht vollstaendig empfangen\n"); exit(1); } dbgstatus[ti->idx] = '2'; // Daten = len Bytes aus dem Stream einlesen nbytes = spbsRecvn(ti->sockfd, buf, len); dbgstatus[ti->idx] = '+'; if ( nbytes < 0 ) { printf("Daten fehlerhaft empfangen\n"); break; } if ( nbytes != len ) { printf("Daten nicht vollstaendig empfangen\n"); break; } #else nleft = sizeof(int); ptr = (char *) &len; while (nleft > 0) { if ( (nread = recv(ti->sockfd, ptr, nleft, 0)) < 0) { printf("ERROR recv\n"); exit (2); } /* end if return < 0 */ else if (nread == 0) break; nleft -= nread; ptr += nread; } /* end while length to receive */ dbgstatus[ti->idx] = '-'; if ( nleft ) { printf("Laenge fehlerhaft empfangen\n"); break; } if (len < 0 || len > 128 ) { printf("Laenge ist falsch\n"); break; } dbgstatus[ti->idx] = '2'; // read data as in Length defined nleft = len; ptr = buf; while (nleft > 0) { if ( (nread = recv(ti->sockfd, ptr, nleft, 0)) < 0) { printf("ERROR recv\n"); exit (2); } /* end if return < 0 */ else if (nread == 0) break; nleft -= nread; ptr += nread; } /* end while length to receive */ dbgstatus[ti->idx] = '+'; if ( nleft ) { printf("Daten fehlerhaft empfangen\n"); break; } #endif /* all received if work .. do here and build the answer */ dbgstatus[ti->idx] = '3'; strcpy(buf,"OK"); len = strlen(buf); /* for OK */ rval = send(ti->sockfd, (char *)&len, sizeof(int), 0); if (rval < 0 || rval != 4) { printf("send Antwortlaenge fehlerhaft\n"); break; } rval = send(ti->sockfd, buf, len, 0); if (rval < 0 || rval != len) { printf("send Antwort fehlerhaft\n"); break; } dbgstatus[ti->idx] = '4'; printf("%d->%s\r", DM_ANZ++,dbgstatus); fflush(stdout); } /* end while */ // Aufraeumen: printf("\nEnde Thread-> %d\n", ti->idx); close(ti->sockfd); dbgstatus[ti->idx] = 'E'; ti->threads[ti->idx] = GOODBYE; --nThreads; free(ti); return NULL; } void sig_break(int signo) { pid_t pid; int stat; close(sockfd); printf("*** terminated\n"); fflush(stdout); exit(0); return; } #ifdef TEST_FEHLER /* recv defined number of bytes */ int spbsRecvn(int fd, void *aptr, int nbytes) { int nleft, nread; char *ptr = aptr; nleft = nbytes; while (nleft > 0) { if ( (nread = recv(fd, ptr, nleft, 0)) < 0) { printf("ERROR spbsRecvn\n"); return -1; } /* end if return < 0 */ else if (nread == 0) break; nleft -= nread; ptr += nread; } /* end while all to receive */ return (nbytes - nleft); // return >= 0 } #endif