Changeset 5eae97a for lib/trace.c


Ignore:
Timestamp:
07/26/05 14:58:21 (15 years ago)
Author:
Shane Alcock <salcock@…>
Branches:
4.0.1-hotfixes, cachetimestamps, develop, dpdk-ndag, etsilive, getfragoff, help, libtrace4, master, ndag_format, pfring, rc-4.0.1, rc-4.0.2, rc-4.0.3, rc-4.0.4, ringdecrementfix, ringperformance, ringtimestampfixes
Children:
dd6e168
Parents:
8c749ae5
Message:

* empty log message *

File:
1 edited

Legend:

Unmodified
Added
Removed
  • lib/trace.c

    rdb06c9d r5eae97a  
    132132#endif
    133133
     134#include <err.h>
    134135
    135136typedef enum {SOCKET, TRACE, STDIN, DEVICE, INTERFACE, RT } source_t;
     
    137138typedef enum {ERF, PCAP, PCAPINT, DAG, RTCLIENT, WAG, WAGINT } format_t;
    138139
     140typedef enum {RTSERVER, GZERF } output_t;
    139141#if HAVE_BPF
    140142/** A type encapsulating a bpf filter
     
    149151#endif
    150152
     153struct libtrace_out_t {
     154        output_t outputformat;
     155
     156        union {
     157                struct {
     158                        char *hostname;
     159                        short port;
     160                } rt;
     161                char *path;
     162                char *interface;
     163        } conn_info;
     164
     165        union {
     166                int fd;
     167#if HAVE_ZLIB
     168                gzFile *file;
     169#else
     170                FILE *file;
     171#endif
     172#if HAVE_PCAP
     173                pcap_t *pcap;
     174#endif
     175        } output;
     176
     177        struct fifo_t *fifo;
     178};
     179
    151180/** The information about traces that are open
    152181 * @internal
     
    155184        format_t format;        /**< The format that this trace is in */
    156185        source_t sourcetype;    /**< The type (device,file, etc */
     186
    157187        union {
    158188                /** Information about rtclients */
     
    177207#endif
    178208        } input;
    179         struct fifo_t *fifo;   
     209
     210        struct fifo_t *fifo;   
    180211        struct {
    181212                void *buf;
     
    393424}
    394425
     426/** Initialises the data contained within the libtrace_out_t structure, based on the provided uri.
     427 *
     428 * @param libtrace      the libtrace_out_t structure to initialise
     429 * @param uri           the uri defining the output type and destination
     430 * @returns             1 if initialised successfully, 0 otherwise
     431 *
     432 * @author Shane Alcock
     433 * */
     434static int init_output(struct libtrace_out_t **libtrace, char *uri) {
     435        char *scan = calloc(sizeof(char),URI_PROTO_LINE);
     436        char *uridata = 0;
     437
     438        // parse the URI to determine what sort of event we are dealing with
     439
     440        // want snippet before the : to get the uri base type.
     441
     442        if((uridata = strchr(uri,':')) == NULL) {
     443                // badly formed URI - needs a :
     444                return 0;
     445        }
     446
     447        if ((*uridata - *uri) > URI_PROTO_LINE) {
     448                // badly formed URI - uri type is too long
     449                return 0;
     450        }
     451        strncpy(scan,uri, (uridata - uri));
     452
     453        if (!strncasecmp(scan,"gzerf",5)) {
     454                (*libtrace)->outputformat = GZERF;
     455        } else if (!strncasecmp(scan, "rt", 2)) {
     456                (*libtrace)->outputformat = RTSERVER;
     457        } else {
     458                return 0;
     459        }
     460
     461        uridata ++;
     462        switch((*libtrace)->outputformat) {
     463                case GZERF:
     464                        /*
     465                         * Acceptable uridata takes the form:
     466                         * /path/to/file.gz
     467                         */
     468                        (*libtrace)->conn_info.path = strdup(uridata);
     469                        break;
     470                case RTSERVER:
     471                        /*
     472                         * Possible uridata formats:
     473                         * hostname
     474                         * hostname:port
     475                         */
     476                        if (strlen(uridata) == 0) {
     477                                (*libtrace)->conn_info.rt.hostname =
     478                                        strdup("localhost");
     479                                (*libtrace)->conn_info.rt.port =
     480                                        COLLECTOR_PORT;
     481                                break;
     482                        }
     483                        if ((scan = strchr(uridata,':')) == NULL) {
     484                                (*libtrace)->conn_info.rt.hostname =
     485                                        strdup(uridata);
     486                                (*libtrace)->conn_info.rt.port =
     487                                        COLLECTOR_PORT;
     488                        } else {
     489                                (*libtrace)->conn_info.rt.hostname =
     490                                        (char *)strndup(uridata,(scan - uridata));
     491
     492                                (*libtrace)->conn_info.rt.port =
     493                                        atoi(++scan);
     494                        }
     495                        break;
     496                default:
     497                        fprintf(stderr, "How did you get here??\n");
     498        }
     499        (*libtrace)->fifo = create_fifo(1048576);
     500        assert( (*libtrace)->fifo);
     501        return 1;
     502}
     503
    395504/** Create a trace file from a URI
    396505 *
     
    565674}
    566675
     676/** Creates a libtrace_out_t structure and the socket / file through which output will be directed.
     677 *
     678 * @param uri   the uri string describing the output format and the destination
     679 * @returns the newly created libtrace_out_t structure
     680 *
     681 * @author Shane Alcock
     682 * */
     683struct libtrace_out_t *trace_output_create(char *uri) {
     684        struct libtrace_out_t *libtrace = malloc(sizeof(struct libtrace_out_t));
     685        struct sockaddr_in remote, client;
     686        int client_fd, clilen;
     687        struct hostent *he;
     688       
     689        if (init_output(&libtrace, uri) == 0)
     690                return 0;
     691
     692        switch(libtrace->outputformat) {
     693                case RTSERVER:
     694                        if ((he=gethostbyname(libtrace->conn_info.rt.hostname)) == NULL) {
     695                                perror("gethostbyname");
     696                                return 0;
     697                        }
     698                        if ((libtrace->output.fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
     699                                perror("socket");
     700                                return 0;
     701                        }
     702                        // Need to set up a listening server here
     703                        bzero((char *) &remote, sizeof(remote));
     704                        remote.sin_family = AF_INET;
     705                        remote.sin_addr.s_addr = INADDR_ANY;
     706                        remote.sin_port = htons(libtrace->conn_info.rt.port);
     707
     708                        if (bind(libtrace->output.fd, (struct sockaddr *) &remote, sizeof(remote)) < 0) {
     709                                perror("bind");
     710                                return 0;
     711                        }
     712                        fprintf(stderr, "Waiting for client to connect\n");
     713
     714                        listen(libtrace->output.fd, 5);
     715                        clilen = sizeof(client);
     716                        if ((client_fd = accept(libtrace->output.fd, (struct sockaddr *) &client, &clilen)) < 0) {
     717                                perror("accept");
     718                                return 0;
     719                        }
     720                        libtrace->output.fd = client_fd;
     721                        fprintf(stderr, "Client connected\n");                       
     722                        break;
     723
     724
     725                case GZERF:
     726/* Catch undefined O_LARGEFILE on *BSD etc */
     727#ifndef O_LARGEFILE
     728#  define O_LARGEFILE 0
     729#endif
     730
     731#if HAVE_ZLIB
     732                        // using gzdopen means we can set O_LARGEFILE
     733                        // ourselves. However, this way is messy and
     734                        // we lose any error checking on "open"
     735                        libtrace->output.file = gzdopen(open(libtrace->conn_info.path, O_CREAT | O_LARGEFILE | O_WRONLY, S_IRUSR | S_IWUSR), "w");
     736#else
     737                        libtrace->output.file = fdopen(open(libtrace->conn_info.path,O_CREAT | O_LARGEFILE | O_WRONLY, S_IRUSR | S_IWUSR), "w");
     738#endif                 
     739                        if (!libtrace->output.file) {
     740                                perror("gzdopen (or fdopen)");
     741                                return 0;
     742                        }
     743                        break;
     744                default:
     745                        fprintf(stderr, "Unrecognised output type - failure to create output instance \n");
     746                        exit(0);
     747        }
     748        return libtrace;
     749}
     750
    567751/** Close a trace file, freeing up any resources it may have been using
    568752 *
     
    592776        destroy_fifo(libtrace->fifo);
    593777        free(libtrace);
     778}
     779
     780/** Close an output trace file, freeing up any resources it may have been using
     781 *
     782 * @param libtrace      the output trace file to be destroyed
     783 *
     784 * @author Shane Alcock
     785 * */
     786void trace_output_destroy(struct libtrace_out_t *libtrace) {
     787        assert(libtrace);
     788
     789        if (libtrace->outputformat == RTSERVER) {
     790                close(libtrace->output.fd);
     791        }
     792        else {
     793#if HAVE_ZLIB
     794                gzclose(libtrace->output.file);
     795#else
     796                fclose(libtrace->output.file);
     797#endif
     798        }
     799        destroy_fifo(libtrace->fifo);
     800        free(libtrace);
    594801}
    595802
     
    8751082
    8761083                assert(size < LIBTRACE_PACKET_BUFSIZE);
    877 
    8781084                // read in the full packet
    8791085                if ((numbytes = fifo_out_read(libtrace->fifo, buffer, size)) == 0) {
     
    8981104}
    8991105
     1106static int trace_write(struct libtrace_out_t *libtrace, void *buffer, size_t len) {
     1107        int numbytes = 0;
     1108
     1109        assert(libtrace);
     1110        assert(len >= 0);
     1111
     1112        if (buffer == NULL) {
     1113                return 0;
     1114        }
     1115
     1116        while (1) {
     1117                switch(libtrace->outputformat) {
     1118                        case RTSERVER:
     1119#ifndef MSG_NOSIGNAL
     1120#define MSG_NOSIGNAL 0
     1121#endif
     1122                                // Write to the network
     1123                                if ((numbytes = send(libtrace->output.fd,
     1124                                                        buffer,
     1125                                                        len,
     1126                                                        MSG_NOSIGNAL)) == -1) {
     1127                                        if (errno == EINTR) {
     1128                                                continue;
     1129                                        }
     1130                                        perror("send");
     1131                                        return -1;
     1132                                }
     1133                                break;
     1134                        case GZERF:                     
     1135#if HAVE_ZLIB
     1136                                if ((numbytes = gzwrite(libtrace->output.file,
     1137                                                        buffer,
     1138                                                        len)) == -1) {
     1139                                        perror("gzwrite");
     1140                                        return -1;
     1141                                }
     1142                                break;
     1143#else
     1144                                // Do binary write instead
     1145                                if ((numbytes = fwrite(buffer, len, 1, libtrace->output.file)) == 0) {
     1146                                        perror("fwrite");
     1147                                        return -1;
     1148                                }
     1149                                break;
     1150#endif
     1151                        default:
     1152                                fprintf(stderr, "Bad output type\n");
     1153                                break;
     1154                }
     1155                break;
     1156        }       
     1157        return numbytes;
     1158}               
     1159
     1160/** Writes a packet to the specified output
     1161 *
     1162 * @param libtrace      describes the output format, destination, etc.
     1163 * @param packet        the packet to be written out
     1164 * @returns the number of bytes written, -1 if write failed
     1165 *
     1166 * @author Shane Alcock
     1167 * */
     1168int trace_write_packet(struct libtrace_out_t *libtrace, struct libtrace_packet_t *packet) {
     1169        // initialise stuff
     1170        int numbytes, size;
     1171        char buf[RP_BUFSIZE];
     1172        int intsize = sizeof(int);
     1173        void *buffer = &buf[intsize];
     1174        int write_required = 0;
     1175
     1176        assert(libtrace);
     1177        assert(packet);
     1178
     1179        if (libtrace->outputformat == GZERF) {
     1180                // do gzwrite
     1181                if ((numbytes = gzwrite(libtrace->output.file, packet->buffer, packet->size)) == 0) {
     1182                        perror("gzwrite");
     1183                        return -1;
     1184                }
     1185                return numbytes;
     1186        }
     1187       
     1188        // do fifo stuff for RT output instead
     1189        if (libtrace->outputformat == RTSERVER) {
     1190                do {
     1191                        assert(libtrace->fifo);
     1192
     1193                        if (fifo_out_available(libtrace->fifo) == 0 || write_required) {
     1194                                // Packet added to fifo
     1195                                if ((numbytes = fifo_write(libtrace->fifo, packet->buffer, packet->size)) == 0) {
     1196                                        // some error with the fifo
     1197                                        perror("fifo_write");
     1198                                        return -1;
     1199                                }
     1200                                write_required = 0;
     1201                        }
     1202                       
     1203                        // Read from fifo and add protocol header
     1204                        if ((numbytes = fifo_out_read(libtrace->fifo, buffer, sizeof(dag_record_t))) == 0) {
     1205                                // failure reading in from fifo
     1206                                fifo_out_reset(libtrace->fifo);
     1207                                write_required = 1;
     1208                                continue;
     1209                        }
     1210                        size = ntohs(((dag_record_t *)buffer)->rlen);           
     1211                        assert(size < LIBTRACE_PACKET_BUFSIZE);
     1212       
     1213                        if ((numbytes = fifo_out_read(libtrace->fifo, buffer, size)) == 0) {
     1214                                // failure reading in from fifo
     1215                                fifo_out_reset(libtrace->fifo);
     1216                                write_required = 1;
     1217                                continue;
     1218                        }
     1219                        fifo_out_update(libtrace->fifo, size); 
     1220                        // Sort out the protocol header
     1221                        memcpy(buf, &packet->status, intsize);
     1222                                               
     1223
     1224                        // Send the buffer out on the wire
     1225                        if ((numbytes = trace_write(libtrace, buf, size + sizeof(int))) <=0 ) {
     1226                                return numbytes;
     1227                        }
     1228
     1229                        // Need an ack to come back
     1230                        // TODO: Obviously this is a little unfinished
     1231                        if ("ACK_ARRIVES") {
     1232                                fifo_ack_update(libtrace->fifo, size);
     1233                                return numbytes;
     1234                        } else {
     1235                                fifo_out_reset(libtrace->fifo);
     1236                        }
     1237                } while(1);
     1238        }
     1239
     1240        // Unacceptable output format
     1241        fprintf(stderr, "Unknown Output format \n");
     1242        assert(0);
     1243}
    9001244
    9011245/** get a pointer to the link layer
Note: See TracChangeset for help on using the changeset viewer.