int mapi_close_flow(int fd) { flowlist_t *flow_item = NULL; if (!minit) { printf("MAPI not initialized! [%s:%d]\n", __FILE__, __LINE__); local_err = MAPI_INIT_ERROR; return -1; } else if (fd <= 0) { printf("ERROR: Wrong fd (fd: %d) in mapi_close_flow\n", fd); return -1; } if (flowlist && (flow_item = flist_get(flowlist, fd)) == NULL) { printf("ERROR: Invalid flow %d [%s:%d]\n", fd, __FILE__, __LINE__); local_err = MAPI_INVALID_FLOW; return -1; } else { flow_item = flist_remove(flowlist,fd); flowdrv_close_flow = drv_get_funct(flow_item->driver, "flowdrv_close_flow"); return (*flowdrv_close_flow)(flow_item); } }
static void cleanup_flow(struct flow *f) { /* delete device if offline flow */ if (f->offline != 0) { mapidrv_delete_device = get_drv_funct(f->drv->handle, "mapidrv_delete_device"); mapidrv_delete_device(f->drv->devid); } else { /* Call driver - ignore error */ mapidrv_close_flow = get_drv_funct(f->drv->handle, "mapidrv_close_flow"); mapidrv_close_flow(f->drv->devid, f->fd); } // clear mapid flow resources f = (struct flow*)flist_remove(flowlist, f->fd); flows--; //FIX:is it ok here to leave flows-- unprotected by locks? /* // clear mapid flow resources f = (struct flow *) flist_remove (flowlist, f->fd); flows--; */ // _may_ be wrong to deallocate free(f); }
/** * closes a flow described by fd * if send_reply is non-zero, a response is sent to client's mapi stub, * (send_reply=0 is used for local clean-ups) */ static void cmd_close_flow(int fd, int pid, int sock, int send_reply) { struct flow *f; struct client *cl; struct mapiipcbuf buf; long file_size; f=(struct flow*)flist_get(flowlist, fd); if (f) { /* to avoid reading memory after it's freed */ int tmpfd = f->fd; /* prevent closing flows of other processes */ if (pid != f->id) { DEBUG_CMD(Debug_Message( "Proc %d tried to close flow %d, which belongs to proc %d", pid, f->fd, f->id)); report_error(MAPI_INVALID_FLOW, pid, sock); return; } cleanup_flow(f); while(__sync_lock_test_and_set(&clientlist_lock,1)); cl = flist_get(clientlist, pid); f = (struct flow *) flist_remove(cl->flowlist, fd); cl->numflows--; clientlist_lock = 0; //send an ACK that flow closed if (send_reply) { buf.mtype = pid; buf.cmd = CLOSE_FLOW_ACK; buf.fd = tmpfd; mapiipc_daemon_write((struct mapiipcbuf *) &buf, sock); if (log_to_file) { file_size = acquire_write_lock(log_fd_info); write_to_file(log_fd_info, "MAPID: flow %d was closed at ", buf.fd); write_date(log_fd_info); write_newline(log_fd_info, "\n"); release_write_lock(log_fd_info, file_size); } if (log_to_syslog) log_message("flow %d was closed", buf.fd); } } else { report_error(MAPI_INVALID_FLOW, pid, sock); } }
int ipfix_decode(anonpacket * p, struct IPFIX *ipfix, struct anonflow *flow) { uint16_t i = 0, j = 0, set_length = 0; unsigned char *payload = NULL; struct ipfix_template_set *tmp_template = NULL; struct ipfix_template_record *tmp_record = NULL; if (!ipfix) return (-1); if (!(p->iph)) return (-1); if (p->data == NULL || p->dsize < sizeof(struct ipfix_header)) return (-1); if (!(p->udph) && !(p->tcph)) return (-1); memset(ipfix, 0, sizeof(struct IPFIX)); payload = (unsigned char *)p->data; ipfix->header = (struct ipfix_header *)payload; payload += sizeof(struct ipfix_header); if (ntohs(ipfix->header->length) > p->dsize) return (-1); // XXX could IPFIX span multiple datagrams? while ((uint16_t) (payload - p->data) < p->dsize) { i = ntohs(*(uint16_t *) payload); if (i == 2) // Template set { ipfix->templates = realloc(ipfix->templates, (++ipfix->ntemplates) * sizeof(struct ipfix_template_set *)); ipfix->templates[ipfix->ntemplates - 1] = malloc(sizeof(struct ipfix_template_set)); ipfix->templates[ipfix->ntemplates - 1]->header = (struct ipfix_set_header *)payload; i = sizeof(struct ipfix_set_header); payload += i; tmp_template = ipfix->templates[ipfix->ntemplates - 1]; tmp_template->nrecords = 0; tmp_template->records = NULL; set_length = ntohs(tmp_template->header->length); while (i < set_length) { if (*(uint16_t *) payload == 0) { // Padding! payload = (unsigned char *)tmp_template->header + ntohs(tmp_template->header->length); break; } tmp_template->records = realloc(tmp_template->records, (++tmp_template->nrecords) * sizeof(struct ipfix_template_record *)); tmp_template->records[tmp_template->nrecords - 1] = malloc(sizeof(struct ipfix_template_record)); tmp_template->records[tmp_template->nrecords - 1]->header = malloc(sizeof(struct ipfix_template_header)); tmp_template->records[tmp_template->nrecords - 1]->header->id = ntohs(((struct ipfix_template_header *)payload)->id); tmp_template->records[tmp_template->nrecords - 1]->header->count = ntohs(((struct ipfix_template_header *)payload)->count); i += sizeof(struct ipfix_template_header); payload += sizeof(struct ipfix_template_header); tmp_record = tmp_template->records[tmp_template->nrecords - 1]; tmp_record->nvendor = tmp_record->nietf = 0; tmp_record->ietf_fields = NULL; tmp_record->vendor_fields = NULL; tmp_record->nfields = ntohs(tmp_record->header->count); tmp_record->fields = malloc(tmp_record->nfields * sizeof(unsigned char *)); for (j = 0; j < tmp_record->nfields; j++) { tmp_record->fields[j] = payload; if (testBit(*payload, 7)) { tmp_record->nvendor++; tmp_record->vendor_fields = realloc(tmp_record->vendor_fields, tmp_record->nvendor * sizeof(struct ipfix_vendor_field_specifier)); tmp_record->vendor_fields[tmp_record->nvendor - 1].id = ntohs(*(uint16_t *) payload); payload += sizeof(uint16_t); tmp_record->vendor_fields[tmp_record->nvendor - 1].length = ntohs(*(uint16_t *) payload); payload += sizeof(uint16_t); tmp_record->vendor_fields[tmp_record->nvendor - 1].enterprise = ntohl(*(uint32_t *) payload); payload += sizeof(uint32_t); i += sizeof(struct ipfix_vendor_field_specifier); } else { tmp_record->nietf++; tmp_record->ietf_fields = realloc(tmp_record->ietf_fields, tmp_record->nietf * sizeof(struct ipfix_ietf_field_specifier)); tmp_record->ietf_fields[tmp_record->nietf - 1].id = ntohs(*(uint16_t *) payload); payload += sizeof(uint16_t); tmp_record->ietf_fields[tmp_record->nietf - 1].length = ntohs(*(uint16_t *) payload); payload += sizeof(uint16_t); i += sizeof(struct ipfix_ietf_field_specifier); } } } // Check against template records with the same ID and replace/insert. struct ipfix_template_record *tmp = NULL; for (j = 0; j < tmp_template->nrecords; j++) { if ((tmp = flist_remove(flow->ipfix_templates, tmp_template->records[j]->header->id, FLIST_LEAVE_DATA)) != NULL) { // free it. } // Insert the new template record. flist_append(flow->ipfix_templates, tmp_template->records[j]->header->id, tmp_template->records[j]); } } else if (i == 3) {// Option Template set } else if (i >= 4 && i <= 255) { // reserved for future use payload += sizeof(uint16_t); payload += ntohs(*(uint16_t *) payload); continue; } else if (i > 256) { // Data set ipfix->data = realloc(ipfix->data, ++(ipfix->ndata) * sizeof(struct ipfix_data_set *)); ipfix->data[ipfix->ndata - 1] = malloc(sizeof(struct ipfix_data_set)); ipfix->data[ipfix->ndata - 1]->header = (struct ipfix_set_header *)payload; ipfix->data[ipfix->ndata - 1]->nfields = 0; payload += sizeof(struct ipfix_set_header); i = sizeof(struct ipfix_set_header); // If you try debugging this, good luck. while (i < ntohs(ipfix->data[ipfix->ndata - 1]->header->length)) { if (*(uint16_t *) payload == 0) { // Padding! payload = (unsigned char *)ipfix->data[ipfix->ndata - 1]->header + ntohs(ipfix->data[ipfix->ndata - 1]->header->length); break; } ipfix->data[ipfix->ndata - 1]->fields = realloc(ipfix->data[ipfix->ndata - 1]->fields, ++(ipfix->data[ipfix->ndata - 1]->nfields) * sizeof(unsigned char *)); ipfix->data[ipfix->ndata - 1]->fields[ipfix->data[ipfix->ndata - 1]->nfields - 1] = payload; payload += ((unsigned char)(*payload & (1 << 8))) ? sizeof(struct ipfix_vendor_field_specifier) : sizeof(struct ipfix_ietf_field_specifier); i += ((unsigned char)(*payload & (1 << 8))) ? sizeof(struct ipfix_vendor_field_specifier) : sizeof(struct ipfix_ietf_field_specifier); } } else return (-1); } return (0); }
/* * Decodes a NetFlow v9 packet. * mfukar * Jan 12 2006 */ int netflow_v9_decode(anonpacket * p, struct NETFLOW_V9 *netflow, struct anonflow *flow) { int i = 0; unsigned char *payload = NULL; int flowsets = 0; uint16_t flowset_length = 0; uint16_t int16 = 0; struct NF9_TEMPLATE_FLOWSET *tmp_template_flowset = NULL; struct NF9_OPTIONS_TEMPLATE *tmp_options_template = NULL; if (!netflow) return (-1); // Expecting a UDP datagram. if (!(p->udph)) return (-1); // We are at least expecting a header. if (p->data == NULL || p->dsize < 20) return (-1); // Initialisations. memset(netflow, 0, sizeof(struct NETFLOW_V9)); payload = p->data; netflow->header = (struct NF9_HEADER *)payload; payload += sizeof(struct NF9_HEADER); // Now get the flowsets. for (flowsets = ntohs(netflow->header->count); flowsets >= 0; flowsets--) { /* * In most cases (ie. all), the header count field doesn't report * the correct number of flowsets. * This ugly piece of code will make sure we don't see any * "additional" flowsets that in fact don't exist. */ if (((uint16_t) (payload - p->data)) >= p->dsize) return (1); //Switch on flowset's ID. int16 = ntohs(*((unsigned short *)payload)); if (int16 == 0) { // Template flowset struct NF9_TEMPLATE *template_cache = NULL; // Allocate memory for the new flowset. netflow->template_flowsets = realloc(netflow->template_flowsets, (++netflow->ntemplates) * sizeof(struct NF9_TEMPLATE_FLOWSET *)); netflow->template_flowsets[netflow->ntemplates - 1] = malloc(sizeof(struct NF9_TEMPLATE_FLOWSET)); netflow->template_flowsets[netflow->ntemplates - 1]->c = (struct NF9_FLOWSET_COMMON *)payload; tmp_template_flowset = netflow->template_flowsets[netflow->ntemplates - 1]; tmp_template_flowset->ntemps = 0; tmp_template_flowset->templates = 0; payload += sizeof(struct NF9_FLOWSET_COMMON); flowset_length = ntohs(tmp_template_flowset->c->length); int16 = sizeof(struct NF9_FLOWSET_COMMON); while (int16 + sizeof(uint16_t) < flowset_length) { template_cache = malloc(sizeof(struct NF9_TEMPLATE)); tmp_template_flowset->templates = realloc(tmp_template_flowset->templates, (++tmp_template_flowset->ntemps) * sizeof(struct NF9_TEMPLATE *)); tmp_template_flowset->templates[tmp_template_flowset->ntemps - 1] = malloc(sizeof(struct NF9_TEMPLATE)); tmp_template_flowset->templates[tmp_template_flowset->ntemps - 1]->inf = (struct NF9_TEMPLATE_INFO *)payload; payload += 2 * sizeof(uint16_t); int16 += 2 * sizeof(uint16_t); tmp_template_flowset->templates[tmp_template_flowset->ntemps - 1]->records = malloc(ntohs (tmp_template_flowset-> templates[tmp_template_flowset->ntemps - 1]->inf->field_count) * sizeof(struct NF9_TEMPLATE_RECORD *)); for (i = 0; i < ntohs(tmp_template_flowset-> templates[tmp_template_flowset->ntemps - 1]->inf->field_count); i++) { tmp_template_flowset->templates[tmp_template_flowset-> ntemps - 1]->records[i] = (struct NF9_TEMPLATE_RECORD *)payload; payload += sizeof(struct NF9_TEMPLATE_RECORD); } int16 += ntohs(tmp_template_flowset-> templates[tmp_template_flowset->ntemps - 1]->inf->field_count) * sizeof(struct NF9_TEMPLATE_RECORD); template_cache->inf = malloc(sizeof(struct NF9_TEMPLATE_INFO)); template_cache->inf->template_id = ntohs(tmp_template_flowset-> templates[tmp_template_flowset->ntemps - 1]->inf->template_id); template_cache->inf->field_count = ntohs(tmp_template_flowset-> templates[tmp_template_flowset->ntemps - 1]->inf->field_count); template_cache->records = malloc(template_cache->inf->field_count * sizeof(struct NF9_TEMPLATE_RECORD *)); for (i = 0; i < template_cache->inf->field_count; i++) { template_cache->records[i] = malloc(sizeof(struct NF9_TEMPLATE_RECORD)); template_cache->records[i]->field_type = ntohs(tmp_template_flowset-> templates[tmp_template_flowset->ntemps - 1]->records[i]->field_type); template_cache->records[i]->field_length = ntohs(tmp_template_flowset-> templates[tmp_template_flowset->ntemps - 1]->records[i]->field_length); } /* * If a template with the same ID already exists, * replace it with this one. */ struct NF9_TEMPLATE *tmp = flist_remove(flow->nf9_templates, template_cache->inf->template_id, FLIST_LEAVE_DATA); if (tmp != NULL) { for (i = 0; i < tmp->inf->field_count; i++) { free(tmp->records[i]); } free(tmp->records); free(tmp->inf); free(tmp); } flist_append(flow->nf9_templates, template_cache->inf->template_id, template_cache); } if (int16 != flowset_length) payload += sizeof(uint16_t); } else if (int16 == 1) { // This is an option template flowset. struct NF9_OPTIONS_TEMPLATE *options = NULL; // Allocate memory for the new flowset. netflow->option_templates = realloc(netflow->option_templates, ++(netflow->noptions) * sizeof(struct NF9_OPTIONS_TEMPLATE *)); netflow->option_templates[netflow->noptions - 1] = malloc(sizeof(struct NF9_OPTIONS_TEMPLATE)); netflow->option_templates[netflow->noptions - 1]->c = (struct NF9_FLOWSET_COMMON *)payload; payload += sizeof(struct NF9_FLOWSET_COMMON); tmp_options_template = netflow->option_templates[netflow->noptions - 1]; tmp_options_template->inf = malloc(sizeof(struct NF9_OPTIONS_INFO)); tmp_options_template->inf = (struct NF9_OPTIONS_INFO *)payload; payload += 3 * sizeof(uint16_t); tmp_options_template->nscopes = tmp_options_template->inf->option_scope_len / sizeof(struct NF9_TEMPLATE_RECORD); tmp_options_template->nopts = tmp_options_template->inf->option_len / sizeof(struct NF9_TEMPLATE_RECORD); // Grab the scope fields. tmp_options_template->scope_fields = malloc(tmp_options_template->nscopes * sizeof(struct NF9_TEMPLATE_RECORD *)); for (i = 0; i < tmp_options_template->nscopes; i++) { tmp_options_template->scope_fields[i] = (struct NF9_TEMPLATE_RECORD *)payload; payload += sizeof(struct NF9_TEMPLATE_RECORD); } // ..and the option fields. tmp_options_template->option_fields = malloc(tmp_options_template->nopts * sizeof(struct NF9_TEMPLATE_RECORD *)); for (i = 0; i < tmp_options_template->nopts; i++) { tmp_options_template->option_fields[i] = (struct NF9_TEMPLATE_RECORD *)payload; payload += sizeof(struct NF9_TEMPLATE_RECORD); } int16 = sizeof(struct NF9_FLOWSET_COMMON) + 3 * sizeof(uint16_t) + tmp_options_template->inf->option_scope_len + tmp_options_template->inf->option_len; if (int16 != flowset_length) payload += sizeof(uint16_t); // Insert the options template flowset in the list. options->c = malloc(sizeof(struct NF9_FLOWSET_COMMON)); options->c->flowset_id = ntohs(tmp_options_template->c->flowset_id); options->c->length = ntohs(tmp_options_template->c->length); options->inf = malloc(sizeof(struct NF9_OPTIONS_INFO)); options->inf->template_id = tmp_options_template->inf->template_id; options->inf->option_scope_len = tmp_options_template->inf->option_scope_len; options->inf->option_len = tmp_options_template->inf->option_len; options->scope_fields = malloc(tmp_options_template->inf->option_scope_len); for (i = 0; i < tmp_options_template->nscopes; i++) { options->scope_fields[i]->field_type = ntohs(tmp_options_template->scope_fields[i]->field_type); options->scope_fields[i]->field_length = ntohs(tmp_options_template->scope_fields[i]->field_length); } options->option_fields = malloc(tmp_options_template->inf->option_len); for (i = 0; i < tmp_options_template->nopts; i++) { options->option_fields[i]->field_type = ntohs(tmp_options_template->option_fields[i]->field_type); options->option_fields[i]->field_length = ntohs(tmp_options_template->option_fields[i]->field_length); } flist_append(flow->nf9_option_templates, options->inf->template_id, options); } else { // This is a data flowset. netflow->data_flowsets = realloc(netflow->data_flowsets, ++(netflow->ndata) * sizeof(struct NF9_DATA_FLOWSET *)); netflow->data_flowsets[netflow->ndata - 1] = malloc(sizeof(struct NF9_DATA_FLOWSET)); netflow->data_flowsets[netflow->ndata - 1]->c = (struct NF9_FLOWSET_COMMON *)payload; netflow->data_flowsets[netflow->ndata - 1]->field_values = payload + sizeof(struct NF9_FLOWSET_COMMON); payload += ntohs(netflow->data_flowsets[netflow->ndata - 1]->c->length); } } return (1); }
static void mapidcom() //Communicates with clients through IPC { fd_set active_fd_set; // active file descriptor list fd_set read_fd_set; // temp file descriptor list for select() int fdmax; // maximum file descriptor number int yes = 1; // for setsockopt() SO_REUSEADDR, below struct sockaddr_un mapidaddr; struct sockaddr_un remoteaddr; struct mapiipcbuf qbuf; socklen_t addrlen; int nbytes, len, s; struct client *cl= NULL; flist_node_t *tmpnode; conf_category_entry_t *cat=NULL; char *local; struct group *mapi_group; conf_category_t *conf; mapidsocket=strdup(MAPIDSOCKGLOBAL); if ((conf = pc_load(mapid_conf)) != NULL) { cat = pc_get_category(conf, ""); local=pc_get_param(cat, "local"); if (local!=NULL && strcmp(local, "1")==0) { free(mapidsocket); mapidsocket=printf_string(MAPIDSOCKHOME, getenv("HOME") ); } pc_close(conf); } // create the listener socket if ((listenerfd = socket(AF_LOCAL, SOCK_STREAM, 0)) == -1) { DEBUG_CMD(Debug_Message("ERROR: socket: %s", strerror(errno))); exit(EXIT_FAILURE); } // avoid "address already in use" error message if (setsockopt(listenerfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { DEBUG_CMD(Debug_Message("ERROR: setsockopt: %s", strerror(errno))); exit(EXIT_FAILURE); } // set up the address we will be binding to memset(&mapidaddr, 0, sizeof (mapidaddr)); mapidaddr.sun_family = AF_LOCAL; memcpy(mapidaddr.sun_path, mapidsocket, strlen(mapidsocket)+1); unlink(mapidsocket); len = sizeof mapidaddr.sun_family + strlen(mapidaddr.sun_path); if (bind(listenerfd, (struct sockaddr *) &mapidaddr, len)) { DEBUG_CMD(Debug_Message("ERROR: bind: %s", strerror(errno))); exit(EXIT_FAILURE); } // allow any member of our own group to connect chmod(mapidsocket, S_IRWXU | S_IRWXG); // if a mapi user group exists, set group permissions accordingly, // otherwise the group ID will be equal to the user ID of the user that // invoked mapid mapi_group = getgrnam(MAPI_GROUP_NAME); if (mapi_group != NULL) { chown(mapidsocket, -1, mapi_group->gr_gid); } if (listen(listenerfd, BACKLOG) == -1) { DEBUG_CMD(Debug_Message("ERROR: listen: %s", strerror(errno))); exit(EXIT_FAILURE); } FD_ZERO (&active_fd_set); // add the listener to the active set FD_SET (listenerfd, &active_fd_set) ; // keep track of the biggest file descriptor fdmax = listenerfd; // so far, it's just this one // wait for commands from the mapi stub, for ever... while (1) { read_fd_set = active_fd_set; // copy it if (select(fdmax + 1, &read_fd_set, NULL, NULL, NULL) == -1) { DEBUG_CMD(Debug_Message("ERROR: select: %s", strerror(errno))); break; } // run through the existing connections for (s = 0; s <= fdmax; s++) { if (FD_ISSET (s, &read_fd_set)) { // connection on the original listener socket if (s == listenerfd) { addrlen = sizeof (remoteaddr); if ((newfd = accept(listenerfd, (struct sockaddr *) &remoteaddr, &addrlen)) == -1) { DEBUG_CMD(Debug_Message("accept: %s", strerror(errno))); } else { FD_SET (newfd, &active_fd_set) ; // add to active set if (newfd > fdmax) { // keep track of the maximum fdmax = newfd; } } } // handle data from an existing client else { if ((nbytes = recv (s, &qbuf, MAX_SEND_SIZE, 0)) <= 0) { if (nbytes == 0) { // connection closed - find client's pid while(__sync_lock_test_and_set(&clientlist_lock,1)); tmpnode = (flist_node_t *) flist_head (clientlist); cl = NULL; while (tmpnode != NULL) { if (((struct client *) tmpnode->data)->sock == s) { cl = (struct client *) tmpnode->data; break; } tmpnode = flist_next (tmpnode); } clientlist_lock = 0; if (cl == NULL) {/* This is not interesting, as it will occur upon requests from clients without flows etc. WARNING_CMD (printf ("WARNING: Zero bytes from socket %d [%s:%d]\n", s, __FILE__, __LINE__)); */ /* shouldn't really exit here? * this will cause the program to exit on errors with an empty * client-list which isn't really an error (IMHO) */ //exit(EXIT_FAILURE); } else { while(__sync_lock_test_and_set(&clientlist_lock,1)); //clean up any remaining flows tmpnode = (flist_node_t *) flist_head (cl->flowlist); while (tmpnode != NULL) { cleanup_flow ((struct flow *) tmpnode->data); tmpnode = flist_next (tmpnode); } tmpnode = (flist_node_t *) flist_head (cl->devicelist); while (tmpnode != NULL) { mapidrv_delete_device = get_drv_funct (tmpnode->data, "mapidrv_delete_device"); mapidrv_delete_device (tmpnode->id); tmpnode = flist_next (tmpnode); } flist_destroy (cl->flowlist); flist_destroy (cl->devicelist); free(cl->devicelist); free (cl->flowlist); //remove this client from global client list free(flist_remove (clientlist, cl->pid)); clientlist_lock = 0; } } else { DEBUG_CMD(Debug_Message("WARNING: recv: %s at", strerror (errno))); } close (s); FD_CLR (s, &active_fd_set); // remove it from active set } else { // we got some data from a client: process request switch (qbuf.cmd) { case GET_LIBS: cmd_get_libs (qbuf.pid, s); break; case GET_LIBPATH: cmd_get_libpath (qbuf.pid, s); break; case CREATE_FLOW: cmd_create_flow ((char *)qbuf.data, qbuf.pid, qbuf.uid, s); break; case CLOSE_FLOW: cmd_close_flow (qbuf.fd, qbuf.pid, s, 1); break; case GET_FLOW_INFO: cmd_get_flow_info (qbuf.fd, qbuf.pid, s); break; case GET_FUNCTION_INFO: cmd_get_function_info (qbuf.fd, qbuf.fid, qbuf.pid, s); break; case GET_NEXT_FUNCTION_INFO: cmd_get_next_function_info (qbuf.fd, qbuf.fid, qbuf.pid, s); break; case GET_NEXT_FLOW_INFO: cmd_get_next_flow_info (qbuf.fd, qbuf.pid, s); break; case GET_NEXT_DEVICE_INFO: cmd_get_next_device_info (qbuf.fd, qbuf.pid, s); break; case GET_DEVICE_INFO: cmd_get_device_info (qbuf.fd, qbuf.pid, s); break; case MAPI_STATS: cmd_stats ((char *)qbuf.data, qbuf.pid, qbuf.uid, s); break; case APPLY_FUNCTION: cmd_apply_function (&qbuf, qbuf.pid, s); break; case READ_RESULT: cmd_read_results (qbuf.fd, qbuf.fid, qbuf.pid, s); break; case CONNECT: cmd_connect (qbuf.fd, qbuf.pid, s); break; case CREATE_FLOW_ACK: case APPLY_FUNCTION_ACK: case READ_RESULT_ACK: case CONNECT_ACK: case CLOSE_FLOW_ACK: case SET_AUTHDATA_ACK: break; case READ_ERROR_ACK: break; case ERROR_ACK: break; case CREATE_OFFLINE_DEVICE: cmd_create_offline_device ((char *)qbuf.data, qbuf.fid, qbuf.pid, s); break; case CREATE_OFFLINE_DEVICE_ACK: break; case START_OFFLINE_DEVICE: cmd_start_offline_device ((char *)qbuf.data, qbuf.pid, s); break; case START_OFFLINE_DEVICE_ACK: break; case DELETE_OFFLINE_DEVICE: cmd_delete_offline_device ((char *)qbuf.data, qbuf.pid, s); break; case DELETE_OFFLINE_DEVICE_ACK: break; case CREATE_OFFLINE_FLOW_ACK: break; case LOAD_LIBRARY: cmd_load_library ((char *)qbuf.data, qbuf.pid, s); default: break; } } } } } // for } // while(1) }