All pastes #519666 Raw Edit

Stuff

public c v1 · immutable
#519666 ·published 2007-05-29 18:50 UTC
rendered paste body
#include <stdio.h>      /* for printf() and fprintf() */#include <sys/socket.h> /* for socket(), bind(), and connect() */#include <arpa/inet.h>  /* for sockaddr_in and inet_ntoa() */#include <stdlib.h>     /* for atoi() and exit() */#include <string.h>     /* for memset() */#include <unistd.h>     /* for close() */#include <pthread.h>#include <sys/select.h>#include <sys/time.h>#include <sys/types.h>#include <signal.h>#include <netdb.h>#include "server.h"#define MAXPENDING 5    /* Maximum outstanding connection requests */#define MAX_THREADS 20   /*anzahl maximaler Nutzer */#define DOMAIN  "bla.com"#define BEGRUSSUNG          "220 " DOMAIN " moin\n"#define FALSCHE_REIHENFOLGE "503 Bad sequence of commands\n"#define FALSCHES_KOMMANDO   "502 Command not implemented\n"#define FALSCHER_PARAMETER  "504 Command parameter not implemented\n"#define HELO_OK             "250 " DOMAIN " OK\n"#define STANDARD_OK         "250 OK\n"#define DATA_BEGIN          "354 Start mail input\n"#define PARAMETER_FALSCH    "501 Syntax error in parameters or arguments\n"#define QUIT_OK             "221 " DOMAIN " closing connection\n"#define BUFFER_SIZE         1024            // buffergroesse#define DATA_SIZE           BUFFER_SIZE*10  //10 fache buffergroesse/* defintion der zustande */#define Z_VERBUNDEN 1#define Z_HELO      2#define Z_MAIL      3#define Z_RECEIPT   4#define Z_DATA      5#define Z_QUIT      6#define Z_RSET      7/* anzahl der zustande */#define BEF_ANZ     7#define SERVER_IP	"mail.informatik.htw-dresden.de"#define SERVER_PORT	25int mask = 0;int servSock;                     /* Socket descriptor fur server */char join_thread[MAX_THREADS];    //feld aktiver threadspthread_t threads[MAX_THREADS];   //fehlt abgearbetieter threadspthread_mutex_t mx_join;          //semeaphore für exkl. zugriff/* zu jedem zustand gehört ein befehl */struct zustaende{    int zustand;    char *kommando;};struct zustaende befehle[]={    {Z_VERBUNDEN, " "},    {Z_HELO, "HELO"},    {Z_MAIL, "MAIL"},    {Z_RECEIPT, "RCPT"},    {Z_DATA, "DATA"},    {Z_QUIT, "QUIT"},    {Z_RSET, "RSET"}};struct speicher{    int data_size;    char* mail_abs;    char* mail_empf;    char* mail_daten;};/* */int daten_lesen(int fd, char* buf, int max_len){    struct timeval tv;      // struktur für zeitwert    fd_set fds;    int ret, len;    FD_ZERO(&fds);    FD_SET(fd, &fds);    if(!mask)        tv.tv_sec = 10;     //10sekunden    else        tv.tv_sec = 600;     //10minuten    tv.tv_usec = 0;     //plus 0 mikrosekunden    ret = select(fd + 1, &fds, NULL, NULL, &tv);    //wartet auf ereignis    if(ret == 0) return 0;    if(ret < 0)    {        perror("select");        return -1;    }    memset(buf, 0, max_len);            //bufffer wird mit 0 initialisiert    len = read(fd, buf, max_len);       //lesen von socket und rückgabe anzahl gelesener bytes    if(len <=0)return 0;    buf[ max_len -1 ]='\0';    return len;}int daten_schreiben(int sock, char* buffer, int len){    int ret=0;    ret = write(sock, buffer, len);    return ret;}/* baut die verbindung korrekt ab */int verbindungsabbau(int sock){    int id = pthread_self();          //ermitteln der eigenen Thread ID    int i, ret=0;    close(sock);                      //schliessen des Sockets    printf("beenden!\n");    /* locked */    pthread_mutex_lock( &mx_join );    for(i=0; i<MAX_THREADS; i++)    {        if(threads[i] == id)          //wenn eintrag in der tabelle der ID entspricht            break;    }    if(i == MAX_THREADS)    {        printf("ganz schlecht!\n");        exit(1);    }    join_thread[i] = 1;    pthread_mutex_unlock( &mx_join );    /* unlocked */    pthread_exit(&ret);             // thread (client) wird beendet    return 0;}int mail_prufen(char *eing, int len, int from, struct speicher *zwischen){    char *ptr, *ptr2;    char* copy = strdup(eing);    if(!from && len < 13)        return -1;    if(from && len < 15)        return -1;    ptr = strsep(&copy, " ");    len -= (copy-ptr);    if(from)    {        if(strncasecmp(copy, "from:", 5) != 0)            return -1;    }    else    {        if(strncasecmp(copy, "to:", 3) != 0)            return -1;    }    ptr = strsep(&copy, ":");    len -= (copy-ptr);    while(len > 0 && copy[0] == 0x20)    {        ptr = strsep(&copy, " ");        len -= (copy-ptr);    }    if(len < 5)        return -1;    if(from)    {        if(zwischen->mail_abs)         {            free(zwischen->mail_abs);            zwischen->mail_abs=NULL;        }        zwischen->mail_abs = (char*) malloc(len);        strncpy(zwischen->mail_abs, copy, len);    }    else    {        if(zwischen->mail_empf)         {            free(zwischen->mail_empf);            zwischen->mail_empf=NULL;        }        zwischen->mail_empf = (char*) malloc(len);        strncpy(zwischen->mail_empf, copy, len);    }    //abschneiden bis zum @    ptr = strsep(&copy, "@");    if(ptr == NULL) //kein @ vorhanden        return -1;    if( (copy-ptr) == 1 ) //@ erstes zeichen        return -1;    len -= (copy-ptr);    if(len <= 0) return -1;    //prufen vor dem @    ptr2 = strsep(&ptr, "\"\\;:");    if(ptr != NULL) //illegales zeichen gefunden        return -1;    //prufen nach dem @    ptr = strsep(&copy, "@\"\\;:");    if(copy != NULL) //illegales zeichen gefunden        return -1;    copy = ptr;    //abschneiden bis zum .    ptr = strsep(&copy, ".");    if(copy == NULL) //kein . vorhanden        return -1;    if( (copy-ptr) == 1 ) //. erstes zeichen nach @        return -1;    len -= (copy-ptr);    if(len <= 0) return -1;    return 0;}int mail_senden(struct speicher *zwischen){    int sock;    struct sockaddr_in server;    struct in_addr a;    struct hostent * host = gethostbyname(SERVER_IP);    unsigned long addr;    char buffer[BUFFER_SIZE];    int len=0;    int size;    char *ptr;    if(host==NULL)    {        printf("falscher host\n");        return -1;    }    if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)    {        perror("smtp socket");        return -1;    }    memcpy((char*)&a, *host->h_addr_list, sizeof(a));    addr=inet_addr(inet_ntoa(a));    memcpy((char *)&server.sin_addr, &addr, sizeof(addr));    server.sin_family = AF_INET;    server.sin_port = htons(SERVER_PORT);    if(connect(sock,(struct sockaddr*)&server,sizeof(server))<0)    {        perror("client: connect");        return -1;    }    //senden der daten    //erst 220 verbunden    memset(buffer, 0, BUFFER_SIZE);    daten_lesen(sock, buffer, BUFFER_SIZE);    if(atoi(buffer) != 220)    {        printf("Fehler anfang %d\n", atoi(buffer));        return -1;    }    //sende HELO    memset(buffer, 0, BUFFER_SIZE);    len = 7+strlen(DOMAIN)+1;    snprintf(buffer, len, "HELO %s\r\n", DOMAIN);    daten_schreiben(sock, buffer, len);    //empfange 250    memset(buffer, 0, BUFFER_SIZE);    daten_lesen(sock, buffer, BUFFER_SIZE);    if(atoi(buffer) != 250)    {        printf("Fehler 2. %d\n", atoi(buffer));        return -1;    }    //sende MAIL FROM:    memset(buffer, 0, BUFFER_SIZE);    len = 12+strlen(zwischen->mail_abs)+1;    snprintf(buffer, len, "MAIL FROM:%s\r\n", zwischen->mail_abs);    daten_schreiben(sock, buffer, len);    //empfange 250    memset(buffer, 0, BUFFER_SIZE);    daten_lesen(sock, buffer, BUFFER_SIZE);    if(atoi(buffer) != 250)    {        printf("Fehler 3. %d\n", atoi(buffer));        return -1;    }    //sende RCPT TO:    memset(buffer, 0, BUFFER_SIZE);    len = 10+strlen(zwischen->mail_abs)+1;    snprintf(buffer, len, "RCPT TO:%s\r\n", zwischen->mail_empf);    daten_schreiben(sock, buffer, len);    //empfange 250    memset(buffer, 0, BUFFER_SIZE);    daten_lesen(sock, buffer, BUFFER_SIZE);    if(atoi(buffer) != 250)    {        printf("Fehler 4. %d\n", atoi(buffer));        return -1;    }    //sende DATA    memset(buffer, 0, BUFFER_SIZE);    len = 7;    snprintf(buffer, len, "DATA\r\n");    daten_schreiben(sock, buffer, len);    //empfange 354    memset(buffer, 0, BUFFER_SIZE);    daten_lesen(sock, buffer, BUFFER_SIZE);    if(atoi(buffer) != 354)    {        printf("Fehler 5. %d\n", atoi(buffer));        return -1;    }    size = zwischen->data_size;    ptr = zwischen->mail_daten;    while( size > 0 )    {        len = (size > BUFFER_SIZE) ? BUFFER_SIZE : size;        len = daten_schreiben(sock, ptr, len);        ptr += len;        size -= len;    }    //empfange 250    memset(buffer, 0, BUFFER_SIZE);    daten_lesen(sock, buffer, BUFFER_SIZE);    if(atoi(buffer) != 250)    {        printf("Fehler 6. %d\n", atoi(buffer));        return -1;    }    //sende QUIT    memset(buffer, 0, BUFFER_SIZE);    len = 7;    snprintf(buffer, len, "QUIT\r\n");    daten_schreiben(sock, buffer, len);    //empfange 221    memset(buffer, 0, BUFFER_SIZE);    daten_lesen(sock, buffer, BUFFER_SIZE);    if(atoi(buffer) != 221)    {        printf("Fehler 7.(ende) %d\n", atoi(buffer));        return -1;    }    return 0;}int daten_prufen(int sock, struct speicher *zwischen){    int ges_len = 0;    int ges_speicher = 0;    int len = 0;    char eing[BUFFER_SIZE];    char *punkt;    if(zwischen->mail_daten != NULL)    {        free(zwischen->mail_daten);        zwischen->mail_daten = (char*) malloc(DATA_SIZE);        ges_speicher = DATA_SIZE;        memset(zwischen->mail_daten, 0, DATA_SIZE);    }    while( (len=daten_lesen(sock, eing, BUFFER_SIZE)) > 0 ) //so labge wir daten lesen    {        if( (ges_len+len) >= ges_speicher)        {            zwischen->mail_daten = realloc(zwischen->mail_daten, (ges_speicher + DATA_SIZE) );            if(zwischen->mail_daten == NULL) return -1;            memset(zwischen->mail_daten + ges_speicher, 0, DATA_SIZE);            ges_speicher = ges_speicher + DATA_SIZE;        }        strncpy(zwischen->mail_daten + ges_len, eing, len );        ges_len += len;        punkt = strstr(zwischen->mail_daten, "\r\n.\r\n");        if( punkt != NULL )        {            zwischen->data_size = ges_len;            return 0;        }    }    return -1;}/*uberpruft die empfangenen Kommandos eines Clients aus Syntax */int prufen(int sock, char* eing, int len, int *zustand, struct speicher *zwischen){    int i=0, bef_len=0, ret=0;    for(i=0; i<BEF_ANZ; i++)    {        bef_len = strlen(befehle[i].kommando);        if(len < bef_len) continue;        if(strncasecmp(eing, befehle[i].kommando, bef_len) == 0)        {            break;        }    }    if(i==BEF_ANZ)    {        daten_schreiben(sock, FALSCHES_KOMMANDO, strlen(FALSCHES_KOMMANDO));        return 0;    }    switch (befehle[i].zustand)     {    case Z_HELO:        if(*zustand == Z_VERBUNDEN)        {            if(len < 6)            {                daten_schreiben(sock, PARAMETER_FALSCH, strlen(PARAMETER_FALSCH));                break;            }            for(i=5; i<len; i++)            {                if(eing[i] > 0x20)                    break;            }            if(i==len)            {                daten_schreiben(sock, PARAMETER_FALSCH, strlen(PARAMETER_FALSCH));                break;            }            daten_schreiben(sock, HELO_OK, strlen(HELO_OK));//             printf("servus \n");            *zustand = Z_HELO;        }        else            daten_schreiben(sock, FALSCHE_REIHENFOLGE, strlen(FALSCHE_REIHENFOLGE));        break;    case Z_MAIL:        if(*zustand == Z_HELO)        {            ret = mail_prufen(eing, len, 1, zwischen);            if(ret < 0)            {                daten_schreiben(sock, PARAMETER_FALSCH, strlen(PARAMETER_FALSCH));                break;            }            daten_schreiben(sock, STANDARD_OK, strlen(STANDARD_OK));//             printf("servus \n");            *zustand = Z_MAIL;        }        else            daten_schreiben(sock, FALSCHE_REIHENFOLGE, strlen(FALSCHE_REIHENFOLGE));        break;    case Z_RECEIPT:        if(*zustand == Z_MAIL)        {            ret = mail_prufen(eing, len, 0, zwischen);            if(ret < 0)            {                daten_schreiben(sock, PARAMETER_FALSCH, strlen(PARAMETER_FALSCH));                break;            }            daten_schreiben(sock, STANDARD_OK, strlen(STANDARD_OK));//             printf("servus \n");            *zustand = Z_RECEIPT;        }        else            daten_schreiben(sock, FALSCHE_REIHENFOLGE, strlen(FALSCHE_REIHENFOLGE));        break;    case Z_DATA:        if(*zustand == Z_RECEIPT)        {            daten_schreiben(sock, DATA_BEGIN, strlen(DATA_BEGIN));//             printf("servus \n");            if(daten_prufen(sock, zwischen) == 0)            {                daten_schreiben(sock, STANDARD_OK, strlen(STANDARD_OK));                *zustand = Z_DATA;                mail_senden(zwischen);            }            else                daten_schreiben(sock, PARAMETER_FALSCH, strlen(PARAMETER_FALSCH));        }        else            daten_schreiben(sock, FALSCHE_REIHENFOLGE, strlen(FALSCHE_REIHENFOLGE));        break;    case Z_QUIT:            daten_schreiben(sock, QUIT_OK, strlen(QUIT_OK));            verbindungsabbau(sock);        break;    case Z_RSET:            *zustand = Z_VERBUNDEN;            daten_schreiben(sock, STANDARD_OK, strlen(STANDARD_OK));        break;    default:        break;    }    return 0;}int eingabemaske(int sock, struct speicher *zwischen){    char buffer[BUFFER_SIZE];    int len, ret, incorrect;    char *list, *tmp;    //absender einlesen    daten_schreiben(sock, "Absender:\n", 11);    len=0;    strcpy(buffer, "MAIL FROM:");    while(len <= 0)        len = daten_lesen(sock, buffer+10, BUFFER_SIZE-10);//     printf("len: %d mailaddy: %s", len-2+10, buffer);    ret = mail_prufen(buffer, len-2+10, 1, zwischen);    if(ret != 0)    {        daten_schreiben(sock, "Emailadresse ungultig!\n", strlen("Emailadresse ungultig!\n"));        return -1;    }    else        daten_schreiben(sock, "Emailadresse korrekt.\n", strlen("Emailadresse korrekt.\n"));    //empfanger einlesen    daten_schreiben(sock, "Empfanger:\n", 12);    do    {        incorrect = 0;        len = 0;        while(len <=0)            len = daten_lesen(sock, buffer+8, BUFFER_SIZE-8);        list = strdup(buffer);        do        {            tmp = strsep(&list, ";");            memset(buffer, 0, BUFFER_SIZE);            strcpy(buffer, "MAIL TO:");            strcat(buffer, tmp);            ret = mail_prufen(buffer, strlen(buffer), 0, zwischen);            if(ret)            {                daten_schreiben(sock, "Emailadresse ungultig!\n", strlen("Emailadresse ungultig!\n"));                incorrect = 1;                break;            }        } while(list);    } while(incorrect);    //daten einlesen    daten_schreiben(sock, "Mailtext:\n", 12);    ret = daten_prufen(sock, zwischen);    if(ret == 0)        daten_schreiben(sock, "daten gepruft\n", strlen("daten gepruft\n"));    else        daten_schreiben(sock, "daten falsch\n", strlen("daten falsch\n"));    ret = mail_senden(zwischen);    if(ret == 0)        daten_schreiben(sock, "daten gesendet\n", strlen("daten gesendet\n"));    else        daten_schreiben(sock, "daten nicht gesendet\n", strlen("daten nicht gesendet\n"));    return 0;}/*fangt das Signal Strg+C ab und beendet alles Verbindugen korrekt*/void sighandler(int sig){    if(sig == SIGINT)    {        printf("caught SIGINT!\n");        close(servSock);        exit(1);    }}/* jeder Thread bekommt diese Funktion übergeben */void handleClient(void* arg){    int sock = *((int*) arg);    char buffer[BUFFER_SIZE];    int ret=0;    int zustand=0;    struct speicher zwischen;    zwischen.mail_abs   = NULL;    zwischen.mail_empf  = NULL;    zwischen.mail_daten = NULL;    if(!mask)        ret = daten_schreiben(sock, BEGRUSSUNG, strlen(BEGRUSSUNG));    if(mask)    {        ret = eingabemaske(sock, &zwischen);    }    else    {        zustand = Z_VERBUNDEN;        for (;;) /* endlos */        {            ret=daten_lesen(sock, buffer, BUFFER_SIZE);            if(ret==0) continue;            if(ret<0) verbindungsabbau(sock);            prufen(sock, buffer, ret, &zustand, &zwischen);            //TODO:REMOVE//             printf("erhalten: %s", buffer);        }    }}int main(int argc, char *argv[]){    int clntSock;                    /* Socket descriptor for server */    struct sockaddr_in smtpServAddr; /* Local address */    struct sockaddr_in smtpClntAddr; /* Client address */    unsigned short smtpServPort;     /* Server port */    fd_set fds;    struct timeval tv;    int ret, i;    unsigned int clntLen;    void *value;    signal(SIGINT, sighandler);       //sighandler initialisierung      pthread_mutex_init( &mx_join, NULL ); //semaphore initialisierung    memset(join_thread, 0, sizeof(join_thread));  //initialisierung der thread tabelle    if (argc != 3)     /* test ob anzahl der argumente korrekt ist */    {        fprintf(stderr, "Usage:  %s <Server Port> <mask [0,1]>\n", argv[0]);        return -1;    }    smtpServPort = atoi(argv[1]);  /* erstes argument:  server port */    mask = atoi(argv[2]);   //maskenwert    /* Socket fur eingehende Verbindungen starten */    if ((servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)    {        perror("socket");        return -1;    }    /* Construct local address structure */    memset(&smtpServAddr, 0, sizeof(smtpServAddr));   /* Zero out structure */    smtpServAddr.sin_family = AF_INET;                /* Internet address family */    smtpServAddr.sin_addr.s_addr = htonl(INADDR_ANY); /* Any incoming interface */    smtpServAddr.sin_port = htons(smtpServPort);      /* Local port */    /* Bind an lokale adresse */    if (bind(servSock, (struct sockaddr *) &smtpServAddr, sizeof(smtpServAddr)) < 0)    {        perror("bind() failed");        return -1;    }    /* socket wird zyklisch abgehort */    if (listen(servSock, MAXPENDING) < 0)    {        perror("listen() failed");        return -1;    }    for (;;) /* endloses warten auf Clienten */    {        /* locked */        pthread_mutex_lock( &mx_join );        for(i=0; i<MAX_THREADS; i++) //maximal MAX_THREADS clienten können sich verbinden, danach warten die weiteren in einer warteschlange        {            if(join_thread[i] == 1)            {                pthread_join(threads[i], &value);                threads[i] = 0;                join_thread[i] = 0;            }        }        pthread_mutex_unlock( &mx_join );        /* unlocked */        FD_ZERO(&fds);        FD_SET(servSock, &fds);        tv.tv_sec = 0;              //zeit zyklus in sek        tv.tv_usec = 50000;         //in mikrosekunden        //hier kommt select und createthread hin        ret = select(servSock + 1, &fds, NULL, NULL, &tv); //wenn etwas auf den Serversocket ankommt        if(ret == 0) continue;                             // bei 0 mach weiter (beendeter Thread)        if(ret < 0) perror("select");                      // bei negativen Werten ist ein Fehler aufgetreten        for(i=0; i<MAX_THREADS; i++)                       // ist noch Platz für einen neuen Client ?            if(threads[i] == 0 ) break;        if(i == MAX_THREADS)                               // wenn nicht kurz warten        {            usleep(10000);            continue;        }         // erzeugen des ClientSockets zur direkten Verbindung        clntSock = accept(servSock, (struct sockaddr *) &smtpClntAddr, &clntLen);        if (clntSock < 0)            perror("accept() failed");        /* clntSock is connected to a client! */        printf("Handling client %s\n", inet_ntoa(smtpClntAddr.sin_addr));        ret = pthread_create(&threads[i], 0, (void*)handleClient, (void*) &clntSock); // jeder client bekommt einen Thread        if( ret != 0)            perror("pthread_create");    }    close(servSock); /* wird nie erreicht */}