コード例 #1
0
ファイル: endianutil.c プロジェクト: KoraST/ft_BIU-1
/* returns 0 on success, -1 on error */
int ft_swap_buf_to_native(UINT16_T command, UINT32_T bufsize, void *buf) {
	datadef_t *ddef;
	
	switch(command) {
		case GET_HDR:
			/* This should not have a buf attached */
			return 0;
		case GET_DAT:
			/* buf contains a datsel_t = 2x UINT32_T */
			if (bufsize == 8) ft_swap32(2, buf);
			return 0;
		case GET_EVT:
			/* buf contains a datsel_t = 2x UINT32_T */
			if (bufsize == 8) ft_swap32(2, buf);
			return 0;
		case WAIT_DAT:
			/* buf contains a waitdef_t = 3x UINT32_T */
			ft_swap32(3, buf);
			return 0;
		case PUT_DAT:
			/* buf contains a datadef_t and after that the data */
			ddef = (datadef_t *) buf;
			ft_swap32(4, ddef);	/* this is for datadef_t */
			ft_swap_data(ddef->nchans*ddef->nsamples, ddef->data_type, ddef + 1); /* ddef+1 points to first data byte */
			return 0;
		case PUT_HDR:
			/* buf contains a headerdef_t and optionally chunks */
			ft_swap32(6, buf);	/* all fields are 32-bit values */
			return ft_swap_chunks_to_native(bufsize - sizeof(headerdef_t), ((headerdef_t *) buf)->nchans, (char *) buf + sizeof(headerdef_t));
		case PUT_EVT:
			/* buf contains multiple eventdef_t and buf's */
			return ft_swap_events_to_native(bufsize, buf);
	}
	return -1;
}
コード例 #2
0
ファイル: endianutil.c プロジェクト: KoraST/ft_BIU-1
int ft_swap_from_native(UINT16_T orgCommand, message_t *msg) {
	datadef_t *ddef;
	UINT32_T nchans;

	UINT32_T bufsize = msg->def->bufsize;
	
	ft_swap16(1, &msg->def->version);
	ft_swap16(1, &msg->def->command);
	ft_swap32(1, &msg->def->bufsize);
	
	if (bufsize == 0) return 0;
	
	switch(orgCommand) {
		case GET_HDR:
			nchans = ((headerdef_t *) msg->buf)->nchans;
			ft_swap32(6, msg->buf);	/* all fields are 32-bit values */
			return ft_swap_chunks_from_native(bufsize - sizeof(headerdef_t), nchans, (char *) msg->buf + sizeof(headerdef_t));
		case GET_DAT:
			ddef = (datadef_t *) msg->buf;
			ft_swap_data(ddef->nchans*ddef->nsamples, ddef->data_type, ddef + 1); /* ddef+1 points to first data byte */
			ft_swap32(5, ddef); /* all fields are 32-bit */
			return 0;
		case GET_EVT:
			return ft_swap_events_from_native(bufsize, msg->buf);
		case WAIT_DAT:
			ft_swap32(2, msg->buf);	/* nsamples + nevents = 32bit */
			return 0;
	}
	return -1;
}
コード例 #3
0
ファイル: endianutil.c プロジェクト: KoraST/ft_BIU-1
int ft_swap_events_from_native(UINT32_T size, void *buf) {
	UINT32_T offset = 0;
	
	while (offset + sizeof(eventdef_t) <= size) {
		unsigned int wst;
		
		eventdef_t *edef = (eventdef_t *) ((char *) buf + offset);
		offset += sizeof(eventdef_t) + edef->bufsize;
		
		wst = wordsize_from_type(edef->type_type);
		
		ft_swap_data(edef->type_numel, edef->type_type, (char *) buf + offset);
		ft_swap_data(edef->value_numel, edef->value_type, (char *) buf + offset + wst*edef->type_numel);
		ft_swap32(8, edef); /* all fields are 32-bit */
	}
	return 0;
}
コード例 #4
0
ファイル: endianutil.c プロジェクト: KoraST/ft_BIU-1
void ft_swap_data(UINT32_T numel, UINT32_T datatype, void *data) {
	switch(datatype) {
		case DATATYPE_CHAR:
		case DATATYPE_UINT8:
		case DATATYPE_INT8:
			return;
		case DATATYPE_UINT16:
		case DATATYPE_INT16:
			ft_swap16(numel, data);
			return;
		case DATATYPE_UINT32:
		case DATATYPE_INT32:
		case DATATYPE_FLOAT32:
			ft_swap32(numel, data);
			return;
		case DATATYPE_UINT64:
		case DATATYPE_INT64:
		case DATATYPE_FLOAT64:
			ft_swap64(numel, data);
			return;
	}	
}
コード例 #5
0
ファイル: endianutil.c プロジェクト: KoraST/ft_BIU-1
int ft_swap_chunks_from_native(UINT32_T size, UINT32_T nchans, void *buf) {
	UINT32_T offset = 0;
	while (offset + sizeof(ft_chunkdef_t) <= size) {
		ft_chunk_t *chunk = (ft_chunk_t *) ((char *) buf + offset);
		offset += sizeof(ft_chunkdef_t) + chunk->def.size;
		
		/* chunk definition fault (=too big) ? */
		if (offset > size) return -1;
		
		switch(chunk->def.type) {
			case FT_CHUNK_RESOLUTIONS:
				if (chunk->def.size >= nchans*sizeof(FLOAT64_T)) {
					ft_swap64(nchans, chunk->data);
				}
				break;
			/* Add other cases here as needed */
		}
		
		ft_swap32(2, &(chunk->def));
	}
	return 0;
}
コード例 #6
0
ファイル: endianutil.c プロジェクト: KoraST/ft_BIU-1
/* returns 0 on success, -1 on error */
int ft_swap_events_to_native(UINT32_T size, void *buf) {
	UINT32_T offset = 0;

	while (offset + sizeof(eventdef_t) <= size) {
		unsigned int wst, wsv;
		
		eventdef_t *edef = (eventdef_t *) ((char *) buf + offset);
		ft_swap32(8, edef); /* all fields are 32-bit */
		
		/* Increase offset to beginning of next event */
		offset += sizeof(eventdef_t) + edef->bufsize;
		if (offset > size) return -1;	/* this event is too big for "buf" */
		
		wst = wordsize_from_type(edef->type_type);
		wsv = wordsize_from_type(edef->value_type);
		
		/* check if type and value fit into this event's local buffer */
		if (wst*edef->type_numel + wsv*edef->value_numel > edef->bufsize) return -1;
		
		ft_swap_data(edef->type_numel, edef->type_type, (char *) buf + offset);
		ft_swap_data(edef->value_numel, edef->value_type, (char *) buf + offset + wst*edef->type_numel);
	}
	return 0;
}
コード例 #7
0
/* this function deals with the incoming client request */
void *tcpsocket(void *arg) {
	int n;
	int status = 0, verbose = 0;
	int oldcancelstate, oldcanceltype;

#ifdef ENABLE_POLLING
	struct pollfd fds;
#endif

	/* these are used for communication over the TCP socket */
	int client = 0;
	message_t *request = NULL, *response = NULL;

    threadlocal_t threadlocal;
    threadlocal.message = NULL;
    threadlocal.fd = -1;

	/* the connection to the client has been made by the server */
	client = (int)arg;

    /* this will be closed at cleanup */
    threadlocal.fd = client;

    pthread_cleanup_push(cleanup_tcpsocket, &threadlocal);

    /* this is for debugging */
    pthread_mutex_lock(&mutexsocketcount);
    socketcount++;
    pthread_mutex_unlock(&mutexsocketcount);

    if (verbose>1) fprintf(stderr, "tcpsocket: client = %d, socketcount = %d, threadcount = %d\n", client, socketcount, threadcount);

	/* keep processing messages untill the connection is closed */
	while (1) {
		int swap = 0;
		UINT16_T reqCommand;
		UINT32_T respBufSize;

		request       = (message_t*)malloc(sizeof(message_t));
		DIE_BAD_MALLOC(request);
		
		request->def  = (messagedef_t*)malloc(sizeof(messagedef_t));
		DIE_BAD_MALLOC(request->def);
		request->buf  = NULL;

#ifdef ENABLE_POLLING
		/* wait for data to become available or until the connection is closed */
		/* thohar: i think this is not neccessary as we dont need a timeout. */
		/* roboos: we need it to detect when the socket is closed by the client */
		while (1) {
			fds.fd      = client;
			fds.events  = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI | POLLOUT | POLLWRNORM | POLLWRBAND | POLLERR | POLLNVAL;
			fds.revents = 0;

			if (poll(&fds, 1, 1)==-1) {
				perror("poll");
				goto cleanup;
			}

			if (fds.revents & POLLHUP)
				goto cleanup;				/* the connection has been closed */
			else if (fds.revents & POLLERR)
				goto cleanup;				/* the connection has been closed */
			else if (fds.revents & POLLIN)
				break;						/* data is available, process the message */
			else
				usleep(POLLSLEEP);			/* wait for data or closed connection */
		}
#endif

		if ((n = bufread(client, request->def, sizeof(messagedef_t))) != sizeof(messagedef_t)) {
			if (verbose>0) fprintf(stderr, "tcpsocket: packet size = %d, should be %d\n", n, sizeof(messagedef_t));
			goto cleanup;
		}
		
		if (request->def->version==VERSION_OE) {
			swap = 1;
			ft_swap16(2, &request->def->version); /* version + command */
			ft_swap32(1, &request->def->bufsize);
			reqCommand = request->def->command;		
		}

		if (request->def->version!=VERSION) {
			if (verbose>0) fprintf(stderr, "tcpsocket: incorrect request version\n");
			goto cleanup;
		}
		
		if (request->def->bufsize>0) {
			request->buf = malloc(request->def->bufsize);
			DIE_BAD_MALLOC(request->buf);
			if ((n = bufread(client, request->buf, request->def->bufsize)) != request->def->bufsize) {
				if (verbose>0) fprintf(stderr, "tcpsocket: read size = %d, should be %d\n", n, request->def->bufsize);
				goto cleanup;
			}
		}
		
		if (swap && request->def->bufsize > 0) ft_swap_buf_to_native(reqCommand, request->def->bufsize, request->buf);

		if (verbose>1) print_request(request->def);
		if (verbose>1) print_buf(request->buf, request->def->bufsize);

		if ((status = dmarequest(request, &response)) != 0) {
			if (verbose>0) fprintf(stderr, "tcpsocket: an unexpected error occurred\n");
			goto cleanup;
		}
		
		DIE_BAD_MALLOC(response);
		DIE_BAD_MALLOC(response->def);
		
		if (verbose>1) print_response(response->def);
		if (verbose>1) print_buf(request->buf, request->def->bufsize);
		
		respBufSize = response->def->bufsize;
		if (swap) ft_swap_from_native(reqCommand, response);

		/* we don't need the request anymore */
		cleanup_message((void**)&request);
		request = NULL;
		
		/* merge response->def and response->buf if they are small, so we can send it in one go over TCP */
		if (respBufSize + sizeof(messagedef_t) <= MERGE_THRESHOLD) {
			int msize = respBufSize + sizeof(messagedef_t);
			void *merged = NULL;
			
			append(&merged, 0, response->def, sizeof(messagedef_t));
			DIE_BAD_MALLOC(merged);
			append(&merged, sizeof(messagedef_t), response->buf, respBufSize);
			DIE_BAD_MALLOC(merged);
						
			if ((n=bufwrite(client, merged, msize) != msize)) {
				if (verbose>0) fprintf(stderr, "tcpsocket: write size = %d, should be %d\n", n, msize);
				FREE(merged);
				goto cleanup;
			}
			FREE(merged);
		} else {
			if ((n = bufwrite(client, response->def, sizeof(messagedef_t)))!=sizeof(messagedef_t)) {
				if (verbose>0) fprintf(stderr, "tcpsocket: write size = %d, should be %d\n", n, sizeof(messagedef_t));
				goto cleanup;
			}
			if ((n = bufwrite(client, response->buf, respBufSize))!=respBufSize) {
				if (verbose>0) fprintf(stderr, "tcpsocket: write size = %d, should be %d\n", n, respBufSize);
				goto cleanup;
			}
		}

		cleanup_message((void**)&response);
        response = NULL;

	} /* while (1) */

cleanup:
    printf(""); /* otherwise the pthread_cleanup_pop won't compile */

	if (response!=NULL) 
		cleanup_message((void**)&response);
	response = NULL;	/* SK: prevent double free in following pthread_cleanup_pop */

	pthread_cleanup_pop(1);

    /* this is for debugging */
    pthread_mutex_lock(&mutexsocketcount);
    socketcount--;
    pthread_mutex_unlock(&mutexsocketcount);

    /* this is for debugging */
    pthread_mutex_lock(&mutexthreadcount);
    threadcount--;
    pthread_mutex_unlock(&mutexthreadcount);

	pthread_exit(NULL);
	return NULL;
}
コード例 #8
0
ファイル: rdaserver.c プロジェクト: Akanoa/PRI
/** Prepares "start" RDA packet with channel names determined from the corresponding chunk (or empty)
	Also converts to little-endian if this machine is big endian
	@param hdr  Points to headerdef_t structure, will be filled, may not be NULL
	@return created start item, or NULL on error (connection / out of memory)
*/
rda_buffer_item_t *rda_aux_get_hdr_prep_start(int ft_buffer, headerdef_t *hdr) {
	rda_buffer_item_t *item = NULL;
	const ft_chunk_t *chunk;
	rda_msg_start_t *R;
	char *str;
	double *dRes;
	const void *dResSource;
	size_t bytesTotal;
	int i,r,numExtraZeros,sizeOrgNames;
	message_t req, *resp = NULL;
	messagedef_t msg_def;	
	
	req.def = &msg_def;
	req.buf = NULL;
	msg_def.version = VERSION;
	msg_def.command = GET_HDR;
	msg_def.bufsize = 0;
	
	r = clientrequest(ft_buffer, &req, &resp);
	if (r<0 || resp == NULL || resp->def == NULL) {
		goto cleanup;
	}
	
	if (resp->def->command != GET_OK || resp->def->bufsize < sizeof(headerdef_t) || resp->buf == NULL) {
		goto cleanup;
	}
	
	memcpy(hdr, resp->buf, sizeof(headerdef_t));
	
	/* Ok, we have the basic header, now look for proper FT_CHUNK_RESOLUTIONS */
	chunk = find_chunk(resp->buf, sizeof(headerdef_t), resp->def->bufsize, FT_CHUNK_RESOLUTIONS);
	if (chunk != NULL && chunk->def.size == hdr->nchans*sizeof(double)) {
		dResSource = chunk->data;
		/* fine - we just need a memcpy later on */
	} else {
		dResSource = NULL;
		/* no suitable chunk found - set defaults later on */
	}
	
	/* Now see if we can find channel names */
	chunk = find_chunk(resp->buf, sizeof(headerdef_t), resp->def->bufsize, FT_CHUNK_CHANNEL_NAMES);
	if (chunk != NULL && chunk->def.size >= hdr->nchans) {
		/* The chunk seems ok - check whether we really have N (0-terminated) strings */
		int k,nz = 0;
		for (k = 0; k<chunk->def.size && nz<=hdr->nchans; k++) {
			if (chunk->data[k] == 0) nz++;
		}
		/* Okay, either k is at the end and we have nz<=N, or we have reached N=nz before the
		   end of the chunk. In both cases, it's safe to transmit the first 'k' bytes and
		   add (N-nz) trailing zeros */
		numExtraZeros = hdr->nchans - nz;
		sizeOrgNames = k;
	} else {
		sizeOrgNames = 0;
		numExtraZeros = hdr->nchans;
	}
	
	bytesTotal = sizeof(rda_msg_start_t) + hdr->nchans*(sizeof(double)) + sizeOrgNames + numExtraZeros;
		
	item = rda_aux_alloc_item(bytesTotal);
	if (item == NULL) goto cleanup;
		
	R = (rda_msg_start_t *) item->data;
	memcpy(R->hdr.guid, _rda_guid, sizeof(_rda_guid));
	R->hdr.nSize = bytesTotal;
	R->hdr.nType = RDA_START_MSG;
	R->nChannels = hdr->nchans;
	R->dSamplingInterval = 1.0e6/(double) hdr->fsample;	/* should be in microseconds */
	
	if (_i_am_big_endian_) {
		/* take care of hdr.nSize, hdr.nType, nChannels */
		ft_swap32(3, &(R->hdr.nSize)); 
		ft_swap64(1, &(R->dSamplingInterval));
	}
	
	/* R+1 points to first byte after header info */
	dRes = (double *) ((void *)(R+1)); 
	if (dResSource == NULL) {
		/* Fill with resolution = 1.0 -- we have nothing better */
		for (i=0;i<hdr->nchans;i++) dRes[i]=1.0;
	} else {
		memcpy(dRes, dResSource, hdr->nchans * sizeof(double));
	}
	/* swap byte order if necessary */
	if (_i_am_big_endian_) {
		ft_swap64(hdr->nchans, dRes);
	}
	
	/* Let 'str' point to first byte after the resolution values */
	str = (char *) ((void *)(dRes + hdr->nchans));
	if (sizeOrgNames > 0) {
		memcpy(str, chunk->data, sizeOrgNames);
	}
	for (i=0;i<numExtraZeros;i++) str[sizeOrgNames + i] = 0;
	
	/* done */
cleanup:
	if (resp) {
		if (resp->def) free(resp->def);
		if (resp->buf) free(resp->buf);
		free(resp);
	}
	return item;
}	
コード例 #9
0
ファイル: rdaserver.c プロジェクト: Akanoa/PRI
/** Retrieves samples and markers and returns them in as a new 'item', or NULL on errors.
*/
rda_buffer_item_t *rda_aux_get_samples_and_markers(int ft_buffer, const samples_events_t *last, const samples_events_t *cur, int numBlock, int use16bit) {
	rda_buffer_item_t *item = NULL;
	int numEvt = 0,numChans = 0,numSmp = 0;
	message_t req, *respSmp = NULL, *respEvt = NULL;
	messagedef_t msg_def;
	datadef_t *ddef;
	size_t bytesSamples = 0, bytesMarkers = 0;
	
	/* First, try to grab the samples */
	if (cur->nsamples > last->nsamples) {
		datasel_t dat_sel;
		
		msg_def.version = VERSION;
		msg_def.command = GET_DAT;
		msg_def.bufsize = sizeof(dat_sel);
		dat_sel.begsample = last->nsamples;
		dat_sel.endsample = cur->nsamples-1;
		req.def = &msg_def;
		req.buf = &dat_sel;
	
		if (clientrequest(ft_buffer, &req, &respSmp)<0) {
			goto cleanup;
		}
		
		numSmp = cur->nsamples - last->nsamples;
		
		if (respSmp == NULL || respSmp->def == NULL || respSmp->buf == NULL || respSmp->def->command != GET_OK) {
			goto cleanup;
		} else {
			ddef = (datadef_t *) respSmp->buf;
			
			if (ddef->nsamples != numSmp) goto cleanup;
			
			numChans = ddef->nchans;
			bytesSamples  = (use16bit ? sizeof(INT16_T) : sizeof(float)) * numSmp * numChans;
		}
	} 
	
	/* Now, try to grab the markers */
	if (cur->nevents > last->nevents) {
		eventsel_t evt_sel;
		int offset = 0;
		
		msg_def.version = VERSION;
		msg_def.command = GET_EVT;
		msg_def.bufsize = sizeof(evt_sel);
		evt_sel.begevent = last->nevents;
		evt_sel.endevent = cur->nevents-1;
		req.def = &msg_def;
		req.buf = &evt_sel;
	
		if (clientrequest(ft_buffer, &req, &respEvt) < 0) {
			goto cleanup;
		}
		if (respEvt == NULL || respEvt->def == NULL || respEvt->buf == NULL || respEvt->def->command != GET_OK) {
			goto cleanup;
		}
		
		/* count the number of events, increase bytesTotal as required */
		while (offset + sizeof(eventdef_t) <= respEvt->def->bufsize) {
			eventdef_t *evdef = (eventdef_t *) ((char *)respEvt->buf + offset);
			offset += sizeof(eventdef_t) + evdef->bufsize;
			
			if (evdef->bufsize < evdef->type_numel*wordsize_from_type(evdef->type_type) + evdef->value_numel*wordsize_from_type(evdef->value_type)) {
				fprintf(stderr,"Invalid event received: Buffer to small for given value/type description\n");
				continue;	/* Skip to next event */
			}
			
			bytesMarkers += sizeof(rda_marker_t);
			if (evdef->type_type == DATATYPE_CHAR) {
				if (evdef->value_type == DATATYPE_CHAR) {
					/* Transform into TYPE:VALUE\0 */
					bytesMarkers += evdef->type_numel + evdef->value_numel + 2;
				} else {
					/* Transform into TYPE:-\0 */
					bytesMarkers += evdef->type_numel + 3;
				}
			} else {
				if (evdef->value_type == DATATYPE_CHAR) {
					/* Transform into FT:VALUE\0 */
					bytesMarkers += evdef->value_numel + 4;
				} else {
					/* Transform into FT:-\0 */
					bytesMarkers += 5; 
				}
			}
			numEvt++;
		}
	}
	
	/* Now, allocate an item with enough space for both samples and markers */
	item = rda_aux_alloc_item(sizeof(rda_msg_data_t) + bytesSamples + bytesMarkers);
	if (item == NULL) {
		fprintf(stderr, "Out of memory\n");
		goto cleanup;
	}
	
	item->blockNumber = numBlock;
	
	/* Okay, we've got the samples in respSmp, events in respEvt, and a big enough 'item'.
		First fill in the header.
	*/
	{
		rda_msg_data_t *R = (rda_msg_data_t *) item->data;

		memcpy(R->hdr.guid, _rda_guid, sizeof(_rda_guid));
		R->hdr.nType = use16bit ? RDA_INT_MSG : RDA_FLOAT_MSG;
		R->hdr.nSize = item->size;
		R->nBlock = numBlock; 
		R->nPoints = numSmp;
		R->nMarkers = numEvt;
		if (_i_am_big_endian_) {
			/* take care of hdr.nSize, hdr.nType, nBlocks, nPoints, nMarkers */
			ft_swap32(5, &(R->hdr.nSize)); 
		}
	}
	
	/* Now, fill in the samples, possibly using conversion */
	if (numSmp > 0) {
		char *dataDest = ((char *) item->data + sizeof(rda_msg_data_t));
		char *dataSrc  = ((char *) respSmp->buf + sizeof(datadef_t));
		int numTotal = numSmp * numChans;
		
		if (use16bit) {
			if (_i_am_big_endian_) {
				/* copy + swap the 16 bit samples */
				int i;
				for (i=0;i<numTotal;i++) {
					dataDest[0] = dataSrc[1];
					dataDest[1] = dataSrc[0];
					dataDest+=2;
					dataSrc+=2;
				}
			} else {
				/* just copy the samples */
				memcpy(dataDest, dataSrc, bytesSamples);
			}
		} else {
			rda_aux_convert_to_float(numTotal, dataDest, ddef->data_type, dataSrc);
			if (_i_am_big_endian_) ft_swap32(numTotal, dataDest);
		}
	}
	
	/* Finally, fill in the events */
	if (numEvt>0) {
		char *ptr = (char *) item->data + sizeof(rda_msg_data_t) + bytesSamples;
		int offset = 0;
		
		/* count the number of events, increase bytesTotal as required */
		while (offset + sizeof(eventdef_t) <= respEvt->def->bufsize) {
			eventdef_t *evdef = (eventdef_t *) ((char *)respEvt->buf + offset);
			char *evbuf = (char *)respEvt->buf + offset + sizeof(eventdef_t);
			rda_marker_t *marker = (rda_marker_t *) ptr;
			int i, markerPos;
			
			offset += sizeof(eventdef_t) + evdef->bufsize;			
			
			if (evdef->bufsize < evdef->type_numel*wordsize_from_type(evdef->type_type) + evdef->value_numel*wordsize_from_type(evdef->value_type)) {
				continue; /* skip to next event */
			}
			
			markerPos = evdef->sample - (last->nsamples +1); /* relative to first sample in this block */
			marker->nPosition = (markerPos > 0) ? markerPos : 0;  /* needs to be unsigned! */
			marker->nChannel  = -1; /* All channels, FieldTrip doesn't have this*/
			marker->nPoints   = evdef->duration;
			
			ptr += sizeof(rda_marker_t);
			
			if (evdef->type_type == DATATYPE_CHAR) {
				/* copy type */
				for (i=0;i<evdef->type_numel;i++) {
					*ptr++ = *evbuf++;
				}
			} else {
				*ptr++ = 'F';
				*ptr++ = 'T';
				/* Skip bytes in event->buffer */
				evbuf += evdef->type_numel;
			}
			*ptr++ = ':';				
			if (evdef->value_type == DATATYPE_CHAR) {
				/* copy value */
				for (i=0;i<evdef->value_numel;i++) {
					*ptr++ = *evbuf++;
				}
			} else {
				*ptr++ = '-';
			}
			/* add trailing 0, see how big the complete marker got */
			*ptr++ = 0;
			marker->nSize = (ptr - (char *) marker);
			
			if (_i_am_big_endian_) {
				/* convert the 4 int32's in the marker definition */
				ft_swap32(4, (void *) marker);
			}
		}		
	} 
	/* Done */
cleanup:
	if (respSmp) {
		FREE(respSmp->buf);
		FREE(respSmp->def);
		free(respSmp);
	}
	if (respEvt) {
		FREE(respEvt->buf);
		FREE(respEvt->def);
		free(respEvt);
	}
	return item;
}
コード例 #10
0
ファイル: socketserver.c プロジェクト: Ascronia/fieldtrip
/************************************************************************
 * This function deals with the incoming client requests in a loop until
 * the user requests to stop the server, or until the remote side closes
 * the connection. The implementation follows the idea of a state machine
 * with the four different states:
 *   state = 0 means we are waiting for a request to come in, or we are
 *             in the process of reading the first 8 bytes (the "def" part)
 *   state = 1 means we are in the process of reading the remainder of
 *             the request (the "buf" part")
 *   state = 2 means we are in the process of writing the response (def)
 *   state = 3 means ... writing the 2nd. part of the response ("buf")
 *
 * On top of those 4 states, we maintain two variables "bytesDone" and
 * "bytesTotal" that determine how many bytes we've read/written within
 * the current state, and how many bytes we need to process in total,
 * and a variable "curPtr" which points to the memory region we currently
 * need to read into, or write from. Whether any action is actually taken
 * inside the while loop also depends on the state of the socket which
 * we find out using "select" (and then set "canRead" + "canWrite" flags).
 *
 * Depending on the nature of the request, we might skip states 1 and 3.
 * This is the case if there is no "buf" attached to the message, or if
 * an outgoing message can be merged in to a single packet.
 * 
 * The actual processing of the message happens before moving to state 2
 * and consists of 
 *   1) possibly swapping the message to native endianness
 *   2) calling dmarequest or the user-supplied callback function
 *   3) possibly swapping back to remote endianness
 ************************************************************************/
void *_buffer_socket_func(void *arg) {
	SOCKET sock;
	ft_buffer_server_t *SC;
	int mergePackets;
	messagedef_t reqdef;
	message_t request;
	message_t *response = NULL;
	int state=0; /* 0 = reading def, 1=reading buf, 2=writing def, 3=writing buf */
	int bytesDone, bytesTotal;
	char mergeBuffer[MERGE_THRESHOLD];
	char *curPtr;	/* points at buffer that needs to be filled or written out */
	int swap = 0;	
	int canRead, canWrite;
	UINT16_T reqCommand;
	UINT32_T respBufSize;
	fd_set readSet, writeSet;

	if (arg==NULL) return NULL;
		
	/* copy over necessary variables and free the given structure */
	SC 			 = ((ft_buffer_socket_t *) arg)->server;
	sock 		 = ((ft_buffer_socket_t *) arg)->clientSocket;
	mergePackets = ((ft_buffer_socket_t *) arg)->mergePackets;
	free(arg);
	
	if (SC->verbosity > 0) {
		printf("Started new client thread with packet merging = %i\n", mergePackets);
	}
	
    pthread_mutex_lock(&SC->lock);
    SC->numClients++;
    pthread_mutex_unlock(&SC->lock);

	request.def = &reqdef;
	request.buf = NULL;
	bytesDone = 0;
	bytesTotal = sizeof(messagedef_t);
	curPtr = (char *) request.def;

	while (SC->keepRunning) {
		int sel, res, n;
		struct timeval tv = {0, 10000}; /* 10ms */
	
		FD_ZERO(&readSet);
		FD_ZERO(&writeSet);
		if (state < 2) {
			FD_SET(sock, &readSet);
		} else {
			FD_SET(sock, &writeSet);
		}
		sel = select((int) sock+1, &readSet, &writeSet, NULL, &tv);
		if (sel == 0) continue;
		if (sel < 0) {
			fprintf(stderr, "Error in 'select' operation - closing client connection.\n");
			break;
		}
		canRead = FD_ISSET(sock, &readSet);
		canWrite = FD_ISSET(sock, &writeSet);
		
		if (canRead) {
			n = recv(sock, curPtr + bytesDone, bytesTotal - bytesDone, 0);
			if (n<=0) {
				/* socket was closed */
				if (SC->verbosity>0) {
					printf("Remote side closed client connection\n");
				}
				break;
			}
			bytesDone+=n;
			if (bytesDone<bytesTotal) continue;
			
			if (state == 0) {
				/* we've read the request.def completely */
				if (reqdef.version==VERSION_OE) {
					swap = 1;
					ft_swap16(2, &reqdef.version); /* version + command */
					ft_swap32(1, &reqdef.bufsize);
					reqCommand = reqdef.command;		
				}
				if (reqdef.version!=VERSION) {
					fprintf(stderr,"Incorrect version requested - closing socket.\n");
					break;
				}
				if (reqdef.bufsize > 0) {
					request.buf = malloc(reqdef.bufsize);
					if (request.buf == NULL) {
						fprintf(stderr, "Out of memory\n");
						break;
					}
					curPtr = request.buf;
					bytesDone = 0;
					bytesTotal = reqdef.bufsize;
					state = 1;
					continue;
				} 
			} else {
				/* Reaching this point means that the state=1, and that we've 
				   read request.buf completely, so swap the endianness if 
				   necessary, and then move on to handling the request.
				*/	
				if (swap) ft_swap_buf_to_native(reqCommand, reqdef.bufsize, request.buf);
			}
			
			/* Request has been read completely, now deal with it */
			if (SC->callback != NULL) {
				/* User supplied a callback function in ft_start_buffer_server */
				res = SC->callback(&request, &response, SC->user_data);
				if (res != 0 || response == NULL || response->def == NULL) {
					fprintf(stderr, "buffer_socket_func: an unexpected error occurred in user-defined request handler\n");
					break;
				}
			} else {
				/* No callback, use normal dmarequest */
				res = dmarequest(&request, &response);
				if (res != 0 || response == NULL || response->def == NULL) {
					fprintf(stderr, "buffer_socket_func: an unexpected error occurred in dmarequest\n");
					break;
				}
			}
			
			/* Ok, the request has been handled, results are in response.
			   We can free the memory pointed to by request.buf ...
			*/
			if (request.buf != NULL) {
				free(request.buf);
				request.buf = NULL;
			}
			
			/* ... swap the response to the remote endianness, if necessary ... */
			respBufSize = response->def->bufsize;
			if (swap) ft_swap_from_native(reqCommand, response);
		
			/* ... and then start writing back the response. To reduce latency,
			   we try to merge response->def and response->buf if they are small, 
			   so we can send it in one go over TCP. To fit the merged packet into 
			   our state machine logic, we apply a trick and jump to state=3 directly,
			   where "curPtr" points to the merged packet.
			   Otherwise, we move to state=2, transmit response->def, move to state=3,
			   and there transmit response->buf.
			*/
			if (mergePackets && respBufSize > 0 && respBufSize + sizeof(messagedef_t) <= MERGE_THRESHOLD) {
				memcpy(mergeBuffer, response->def, sizeof(messagedef_t));
				memcpy(mergeBuffer + sizeof(messagedef_t), response->buf, respBufSize);
				
				curPtr = mergeBuffer;
				bytesDone = 0;
				bytesTotal = respBufSize + sizeof(messagedef_t);
				state = 3;
			} else {
				curPtr = (char *) response->def;
				bytesDone = 0;
				bytesTotal = sizeof(messagedef_t);
				state = 2;
			}
			canWrite = 1;
		}
		
		if (state >= 2 && canWrite) {
			n = send(sock, curPtr + bytesDone, bytesTotal - bytesDone, 0);
			if (n<=0) {
				/* socket was closed */
				fprintf(stderr, "Cannot write to socket -- closing client connection.\n");
				break;
			}
			bytesDone+=n;
			if (bytesDone < bytesTotal) continue;
			if (state==2 && respBufSize > 0) {
				curPtr = (char *) response->buf;
				bytesDone = 0;
				bytesTotal = respBufSize;
				state = 3;
				continue;
			}
			/* Reaching this point means we are done with writing out the response,
			   so we will now free the allocated memory, and reset to state=0.
			*/
			if (response->buf) free(response->buf);
			free(response->def);
			free(response);
			response = NULL;
			state = 0;
			curPtr = (char *) request.def;
			bytesDone = 0;
			bytesTotal = sizeof(messagedef_t);
		}
	}
	
    pthread_mutex_lock(&SC->lock);
    SC->numClients--;
    pthread_mutex_unlock(&SC->lock);
	
	closesocket(sock);
	if (request.buf!=NULL) free(request.buf);
    if (response!=NULL) {
		if (response->buf!=NULL) free(response->buf);
		if (response->def!=NULL) free(response->def);
		free(response);
	}
	
	return NULL;
}