I have a xml and schema which I want to validate. I don't want schema to be stored in file, but in database location. I use xmlSchemaNewMemParserCtxt to parse the schema. The problem is that this schema references another schema for basic types: <xs:include schemaLocation="CommonTypes.xsd"/>, which libXml2 searches in the current working directory. Is there any way to supply these additional schemas in memory buffer?
xmlRegisterInputCallbacks is what you're probably looking for.
The advantage, they let you construct some kind of a virtual I/O layer. The disadvantage, inputcallbacks are set globally (there is however xmlPopInputCallbacks and xmlCleanupInputCallbacks).
The code below (built upon code from http://knol2share.blogspot.be) demonstrates the use of xmlRegisterInputCallbacks.
All xml and xsd files are loaded from the file system, except when the URI contains "DataTypes.xsd" the schema is fetched from a string. (since schemaLocation is only a hint one could for example prefix schema's
"test.xsd": the main xml schema (please ignore the reference to peacelane.org, namespaces are from a hobby project, just occurred to me now www.peacelane.org might exist, apparently it does...)
<schema xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://peacelane.org/ApplianceType/config/45/LIGHTING1/ARC"
xmlns:dt="http://peacelane.org/ApplianceType/config/45/DataTypes"
targetNamespace="http://peacelane.org/ApplianceType/config/45/LIGHTING1/ARC"
elementFormDefault="qualified">
<import namespace="http://peacelane.org/ApplianceType/config/45/DataTypes" schemaLocation="DataTypes.xsd" />
<complexType name="ConfigType">
<sequence>
<element name="housecode" type="dt:char" />
</sequence>
</complexType>
<element name="Config" type="tns:ConfigType"/>
</schema>
"test.xml": a test xml to validate
<?xml version="1.0"?>
<Config xmlns="http://peacelane.org/ApplianceType/config/45/LIGHTING1/ARC">
<housecode>A</housecode>
</Config>
"main.c": the actual code (update the paths for "XMLFileName" and "XSDFileName")
#define LIBXML_SCHEMAS_ENABLED
#include <libxml/xmlschemastypes.h>
#include <stdio.h>
static const char *databaseSchema =
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
" <schema elementFormDefault=\"qualified\" xmlns:tns=\"http://peacelane.org/ApplianceType/config/45/DataTypes\" targetNamespace=\"http://peacelane.org/ApplianceType/config/45/DataTypes\" xmlns=\"http://www.w3.org/2001/XMLSchema\">"
" <simpleType name=\"char\">"
" <restriction base=\"string\">"
" <length value=\"1\" />"
" </restriction>"
" </simpleType>"
" </schema>";
//-----------------------------------------------------------------------------
//-- SQL Callbacks (~ simulated db actions)
//-----------------------------------------------------------------------------
static void* sqlOpen(const char * URI) {
return ((void *) databaseSchema );
}
static int sqlClose(void * context) {
return (0);
}
static int sqlRead(void * context, char * buffer, int len) {
const char* result= (const char *) context;
int rlen = strlen(result);
memcpy(buffer, result, rlen);
return rlen +1;
}
static int sqlMatch(const char * URI) {
if ((URI != NULL )&& (strstr(URI, "DataTypes.xsd") != NULL) )return 1;
return 0;
}
//-----------------------------------------------------------------------------
//-- File callbacks
//-----------------------------------------------------------------------------
static void* fileOpen(const char * URI) {
if (URI == NULL )
return (NULL );
FILE* fh = fopen(URI, "rt");
return ((void *) fh);
}
static int fileClose(void * context) {
FILE* fh = (FILE*) context;
if (fh != NULL )
fclose(fh);
return (0);
}
static int fileRead(void * context, char * buffer, int len) {
FILE* fh = (FILE*) context;
fseek(fh, 0L, SEEK_END);
long flen = ftell(fh);
rewind(fh);
if (buffer != NULL )
fread(buffer, flen, 1, fh);
return flen + 1;
}
static int fileMatch(const char * URI) {
if ((URI != NULL ))
if (strstr(URI, "DataTypes.xsd") == NULL ) {
return (1);
}
return (0);
}
//-----------------------------------------------------------------------------
//-- Main
//-----------------------------------------------------------------------------
int main(int argc, char *argv[]) {
xmlDocPtr doc;
xmlSchemaPtr schema = NULL;
xmlSchemaParserCtxtPtr ctxt;
char *XMLFileName =
"/home/dogguts/Projects/libxml2tests/xsdparse/Debug/test.xml";
char *XSDFileName =
"/home/dogguts/Projects/libxml2tests/xsdparse/Debug/test.xsd";
xmlLineNumbersDefault(1);
if (xmlRegisterInputCallbacks(fileMatch, fileOpen, fileRead, fileClose)
< 0) {
fprintf(stderr, "failed to register File handler\n");
exit(1);
}
if (xmlRegisterInputCallbacks(sqlMatch, sqlOpen, sqlRead, sqlClose) < 0) {
fprintf(stderr, "failed to register SQL handler\n");
exit(1);
}
ctxt = xmlSchemaNewParserCtxt(XSDFileName);
xmlSchemaSetParserErrors(ctxt, (xmlSchemaValidityErrorFunc) fprintf,
(xmlSchemaValidityWarningFunc) fprintf, stderr);
schema = xmlSchemaParse(ctxt);
xmlSchemaFreeParserCtxt(ctxt);
xmlSchemaDump(stdout, schema);
doc = xmlReadFile(XMLFileName, NULL, 0);
if (doc == NULL ) {
fprintf(stderr, "Could not parse %s\n", XMLFileName);
} else {
xmlSchemaValidCtxtPtr ctxt;
int ret;
ctxt = xmlSchemaNewValidCtxt(schema);
xmlSchemaSetValidErrors(ctxt, (xmlSchemaValidityErrorFunc) fprintf,
(xmlSchemaValidityWarningFunc) fprintf, stderr);
ret = xmlSchemaValidateDoc(ctxt, doc);
if (ret == 0) {
printf("%s validates\n", XMLFileName);
} else if (ret > 0) {
printf("%s fails to validate\n", XMLFileName);
} else {
printf("%s validation generated an internal error\n", XMLFileName);
}
xmlSchemaFreeValidCtxt(ctxt);
xmlFreeDoc(doc);
}
if (schema != NULL )
xmlSchemaFree(schema);
xmlSchemaCleanupTypes();
xmlCleanupParser();
xmlMemoryDump();
return (0);
}
Notice that, for brevity, the above code doesnt' perform any checks wether (file, memory,...) operations succeeded.
This is a better example how to do it: io1.c
http://www.xmlsoft.org/examples/
It saves a lot of time when you can find what is good way to return value from Read function.
Related
Hi I tried to write my own version of memmove and I find the following code resulting in a segmentation fault. It would be great if someone could help me figure out why this behavior would occur!
However, when I use something like:
char source[20] = "Hello, this is Piranava", the code works fine!
void *memmoveLocal(void *dest, const void *src, unsigned int n)
{
char *destL = dest;
const char *srcL = src;
int i = 0;
if(dest == NULL || src == NULL)
{
return NULL;
}
else
{
// if dest comes before source, even if there's an overlap, we should move forward
// because if there's an overlap (when dest < src) and we move backward, we'd overwrite the overlapping bytes in src
if(destL < srcL)
{
printf("Forward\n");
while(i < n)
{
destL[i] = srcL[i];
i++;
}
}
else // in all other cases (even if there's overlap or no overlap, we can move backward)
{
printf("Backward\n");
i = n - 1;
while(i >= 0)
{
destL[i] = srcL[i];
i--;
}
}
}
return dest;
}
void main()
{
char *source = "Hello, this is ABC";
char *destination = malloc(strlen(source)+1);
memmoveLocal(source+5, source, 5);
printf("Source: %s \nDestination: %s, size: %d\n", source, destination, strlen(destination));
}
However, if I replace
char *source = "Hello, this is ABC";
with
char source[20] = "Hello, this is ABC";
, it works fine!
memmoveLocal(source+5, source, 5);
You are trying to overwrite a string literal, which is not writable.
Did you intend to memmoveLocal(destination, source+5, 5) instead?
char source[20] = "Hello, this is ABC";
That turns source from a string literal into a char[] array initialized with a string literal. The array is writable, so your program no longer crashes.
I need to decode rtsp stream from Ip camera using ffmpeg, below is the code for decoder
ffmpeg_decoder.h
class ffmpeg_decoder
{
public:
ffmpeg_decoder();
int initial(QString & url);
int h264Decodec();
void close_stream();
virtual ~ffmpeg_decoder();
AVPicture picture;
int width;
int height;
QMutex mutex;
QImage imageDecoded;
private:
AVFormatContext *pFormatCtx;
AVCodecContext *pCodecCtx;
AVFrame *pFrame;
AVPacket packet;
SwsContext * pSwsCtx;
int videoStream;
QString rtspURL;
};
ffmpeg_decoder.cpp
ffmpeg_decoder::ffmpeg_decoder()
{
pCodecCtx = NULL;
videoStream=-1;
}
ffmpeg_decoder::~ffmpeg_decoder()
{
sws_freeContext(pSwsCtx);
}
int ffmpeg_decoder::initial(QString & url)
{
int err;
rtspURL=url;
AVCodec *pCodec;
av_register_all();
avformat_network_init();
pFormatCtx = avformat_alloc_context();
pFrame = av_frame_alloc();
err = avformat_open_input(&pFormatCtx, rtspURL.toStdString().c_str(), NULL,
NULL);
if (err < 0)
{
printf("Can not open this file");
return -1;
}
if (avformat_find_stream_info(pFormatCtx,NULL) < 0)
{
printf("Unable to get stream info");
return -1;
}
int i = 0;
videoStream = -1;
for (i = 0; i < pFormatCtx->nb_streams; i++)
{
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
videoStream = i;
break;
}
}
if (videoStream == -1)
{
printf("Unable to find video stream");
return -1;
}
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
width=pCodecCtx->width;
height=pCodecCtx->height;
avpicture_alloc(&picture,PIX_FMT_RGB24,pCodecCtx->width,pCodecCtx->height);
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
pSwsCtx = sws_getContext(width, height, PIX_FMT_YUV420P, width,
height, PIX_FMT_RGB24,
SWS_BICUBIC, 0, 0, 0);
if (pCodec == NULL)
{
printf("Unsupported codec");
return -1;
}
printf("video size : width=%d height=%d \n", pCodecCtx->width,
pCodecCtx->height);
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
{
printf("Unable to open codec");
return -1;
}
printf("initial successfully");
return 0;
}
int ffmpeg_decoder::h264Decodec()
{
int frameFinished=0;
// while (av_read_frame(pFormatCtx, &packet) >= 0)
if(av_read_frame(pFormatCtx, &packet) >= 0)
{
if(packet.stream_index==videoStream)
{
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
if (frameFinished)
{
printf("***************ffmpeg decodec*******************\n");
mutex.lock();
int rs = sws_scale(pSwsCtx, (const uint8_t* const *) pFrame->data,
pFrame->linesize, 0,
height, picture.data, picture.linesize);
imageDecoded = QImage();
imageDecoded= QImage(this->picture.data[0],this->width,this->height,QImage::Format_RGB888);
//imageDecoded = imageDecoded.copy();
mutex.unlock();
if (rs == -1)
{
printf("__________Can open to change to des imag_____________e\n");
return -1;
}
}
}
}
av_free_packet(&packet);
av_frame_unref(pFrame);
av_packet_unref(&packet);
avpicture_free(&picture);
return 1;
}
void ffmpeg_decoder::close_stream(){
/*if (pFrame)
av_free(&pFrame);*/
if (pCodecCtx)
avcodec_close(pCodecCtx);
if (pSwsCtx)
sws_freeContext(pSwsCtx);
avpicture_free(&picture);
if (pFormatCtx)
avformat_close_input(&pFormatCtx);
}
Below is the main thread which do the decoding.
I am using Qt for creating thread and do decoding
ffmpeg_decoder * ffmpeg = new ffmpeg_decoder();;
if(ffmpeg->initial(rtspURL)==0){
while (1) {
ffmpeg->h264Decodec();
//get frame and do processing right now it disabled, and still see the memory leak.
.......
if(stopFlg.load()==1)
break;
}
//close stream if break
ffmpeg->close_stream();
}
else {
ffmpeg->close_stream();
}
When I run 36 thread with different URL I can see the memory usage of the program increase over time.
I have used valgrind to detect the leak, and here is the relevant part of the log
This is the first memory leak location
=14402== by 0x692017F: av_malloc (in /usr/lib/x86_64-linux-gnu/libavutil-ffmpeg.so.54.31.100)
==14402== by 0x692048D: av_mallocz (in /usr/lib/x86_64-linux-gnu/libavutil-ffmpeg.so.54.31.100)
==14402== by 0x691915E: av_frame_alloc (in /usr/lib/x86_64-linux-gnu/libavutil-ffmpeg.so.54.31.100)
==14402== by 0x419663: ffmpeg_decoder::initial(QString&) (ffmpeg_decoder.cpp:24)
==14402== by 0x41ABEC: RTSP_Player_Object::run() (rtsp_player_object.cpp:15)
Another
==14402== 2,176 bytes in 16 blocks are indirectly lost in loss record 23,113 of 23,379
==14402== at 0x4C2E0EF: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==14402== by 0x7780A4E: QImageData::create(unsigned char*, int, int, int, QImage::Format, bool, void (*)(void*), void*) (in /home/vapplica/Qt5.11.1/5.11.1/gcc_64/lib/libQt5Gui.so.5.11.1)
==14402== by 0x7780C30: QImage::QImage(unsigned char*, int, int, QImage::Format, void (*)(void*), void*) (in /home/vapplica/Qt5.11.1/5.11.1/gcc_64/lib/libQt5Gui.so.5.11.1)
==14402== by 0x419B21: ffmpeg_decoder::h264Decodec() (ffmpeg_decoder.cpp:96)
I have check the documentation and sample on ffmpeg site, and I think I am releasing the allocated memory, but still I can see the memory leak when I run the program.
I have created a shared memory segment with the help of a binary in C and written some data into it. Now I want read that data from Qt. How to attach to existing shared memory from Qt?
QSharedMemory isn't really meant to interoperate with anything else. On Unix, it is implemented via SYSV shared memory, but it passes Qt-specific arguments to ftok:
::ftok(filename.constData(), qHash(filename, proj_id));
You could emulate this behavior in your C code, but I don't think it's necessary.
Instead of opening a shared memory segment, simply map a file to memory, and access it from multiple processes. On Qt, QFile::map does what you need.
The example below shows both techniques: using SYSV shared memory and using memory-mapped files:
// https://github.com/KubaO/stackoverflown/tree/master/questions/sharedmem-interop-39573295
#include <QtCore>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <cerrno>
#include <stdexcept>
#include <string>
First, let's have a shared data structure.
struct Data {
int a = 1;
bool b = true;
char c = 'S';
bool operator==(const Data & o) const { return o.a == a && o.b == b && o.c == c; }
static void compare(const void * a, const void * b) {
auto data1 = reinterpret_cast<const Data*>(a);
auto data2 = reinterpret_cast<const Data*>(b);
Q_ASSERT(*data1 == *data2);
}
};
We definitely want error checking, so let's add some helpers that make that easier:
void check(bool ok, const char * msg, const char * detail) {
if (ok) return;
std::string str{msg};
str.append(": ");
str.append(detail);
throw std::runtime_error{str};
}
void check(int f, const char * msg) { check(f != -1, msg, strerror(errno)); }
void check(void * f, const char * msg) { check(f != MAP_FAILED, msg, strerror(errno)); }
void check(bool rc, const QSharedMemory & shm, const char * msg) { check(rc, msg, shm.errorString().toLocal8Bit()); }
void check(bool rc, const QFile & file, const char * msg) { check(rc, msg, file.errorString().toLocal8Bit()); }
And we need RAII wrappers for C APIs:
struct noncopyable { Q_DISABLE_COPY(noncopyable) noncopyable() {} };
struct ShmId : noncopyable {
int id;
ShmId(int id) : id{id} {}
~ShmId() { if (id != -1) shmctl(id, IPC_RMID, NULL); }
};
struct ShmPtr : noncopyable {
void * ptr;
ShmPtr(void * ptr) : ptr{ptr} {}
~ShmPtr() { if (ptr != (void*)-1) shmdt(ptr); }
};
struct Handle : noncopyable {
int fd;
Handle(int fd) : fd{fd} {}
~Handle() { if (fd != -1) close(fd); }
};
Here's how to interoperates SYSV shared memory sections between C and Qt. Unfortunately, unless you reimplement qHash in C, it's not possible:
void ipc_shm_test() {
QTemporaryFile shmFile;
check(shmFile.open(), shmFile, "shmFile.open");
// SYSV SHM
auto nativeKey = QFile::encodeName(shmFile.fileName());
auto key = ftok(nativeKey.constData(), qHash(nativeKey, 'Q'));
check(key, "ftok");
ShmId id{shmget(key, sizeof(Data), IPC_CREAT | 0600)};
check(id.id, "shmget");
ShmPtr ptr1{shmat(id.id, NULL, 0)};
check(ptr1.ptr, "shmat");
new (ptr1.ptr) Data;
// Qt
QSharedMemory shm;
shm.setNativeKey(shmFile.fileName());
check(shm.attach(QSharedMemory::ReadOnly), shm, "shm.attach");
auto ptr2 = shm.constData();
Data::compare(ptr1.ptr, ptr2);
}
Here's how to interoperate memory-mapped files:
void mmap_test() {
QTemporaryFile shmFile;
check(shmFile.open(), "shmFile.open");
shmFile.write({sizeof(Data), 0});
check(true, shmFile, "shmFile.write");
check(shmFile.flush(), shmFile, "shmFile.flush");
// SYSV MMAP
Handle fd{open(QFile::encodeName(shmFile.fileName()), O_RDWR)};
check(fd.fd, "open");
auto ptr1 = mmap(NULL, sizeof(Data), PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd.fd, 0);
check(ptr1, "mmap");
new (ptr1) Data;
// Qt
auto ptr2 = shmFile.map(0, sizeof(Data));
Data::compare(ptr1, ptr2);
}
And finally, the test harness:
int main() {
try {
ipc_shm_test();
mmap_test();
}
catch (const std::runtime_error & e) {
qWarning() << e.what();
return 1;
}
return 0;
}
I was trying to come up with a program that will use a linked list to read data off a file and delete grades that are under 50%. I came up with this code but it gives me the error "type float' argument given todelete', expected pointer". Please help if you can.
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#include<string.h>
struct node
{
int id;
char name[10];
float grade;
struct node * next;
};
void build_link(struct node * ap);
void happy (struct node * bp);
void delete_fail (struct node *np);
int main(int argc, char *argv[])
{
struct node head;
head.next = NULL;
build_link( &head);
happy(head.next);
delete_fail (head.next);
system("PAUSE");
return 0;
}
void build_link(struct node * tmp)
{
int nu_id;
char nu_nam[10];
float nu_grade;
struct node * np;
FILE *fp;
fp = fopen("Student.txt","r");
while (fscanf( fp,"%d %s %f", &nu_id, nu_nam, &nu_grade ) != EOF)
{
np = (struct node *) malloc ( sizeof (struct node) );
strcpy (np->name,nu_nam);
np->id = nu_id;
np->grade = nu_grade;
np->next = NULL;
tmp->next = np;
tmp = tmp->next;
}
}
void happy(struct node *np)
{
while (np != NULL)
{
printf(" %d %s %f \n", np->id, np->name, np->grade);
np = np->next;
}
}
void delete_fail(struct node* grade)
{
node *np;
if(np == NULL)
printf("\nElement not found");
else
{
This is where my problem lies. I am not sure how to fix this part right here.
if( np->grade <50 )
np->grade = delete(np->grade);**
else
if(np->grade > 60)
np->grade = np->grade;
}
}
I am currently making a simple client and server but I have run into an issue. Part of the system is for the client to query about a local file on the server. The contents of that file must be then sent to the client. I am able to send all the text within a file to the client however it seems to be stuck in the read loop on the client. Below are the code spits for both the client and server that are meant to deal with this:
Client Code That Reads The Loop
else if(strcmp(commandCopy, get) == 0)
{
char *ptr;
int total = 0;
char *arguments[1024];
char copy[2000];
char * temp;
int rc;
strcpy(copy, command);
ptr = strtok(copy," ");
while (ptr != NULL)
{
temp = (char *)malloc(sizeof(ptr));
temp = ptr;
arguments[total] = temp;
total++;
ptr = strtok (NULL, " ");
}
if(total == 4)
{
if (strcmp(arguments[2], "-f") == 0)
{
printf("1111111111111");
send(sockfd, command, sizeof(command), 0 );
printf("sent %s\n", command);
memset(&command, '\0', sizeof(command));
cc = recv(sockfd, command, 2000, 0);
if (cc == 0)
{
exit(0);
}
}
else
{
printf("Here");
strcpy(command, "a");
send(sockfd, command, sizeof(command), 0 );
printf("sent %s\n", command);
memset(&command, '\0', sizeof(command));
cc = recv(sockfd, command, 2000, 0);
}
}
else
{
send(sockfd, command, sizeof(command), 0 );
printf("sent %s\n", command);
memset(&command, '\0', sizeof(command));
while ((rc = read(sockfd, command, 1000)) > 0)
{
printf("%s", command);
}
if (rc)
perror("read");
}
}
Server Code That Reads the File
char* getRequest(char buf[], int fd)
{
char * ptr;
char results[1000];
int total = 0;
char *arguments[1024];
char data[100];
FILE * pFile;
pFile = fopen("test.txt", "r");
ptr = strtok(buf," ");
while (ptr != NULL)
{
char * temp;
temp = (char *)malloc(sizeof(ptr));
temp = ptr;
arguments[total] = temp;
total++;
ptr = strtok (NULL, " ");
}
if(total < 2)
{
strcpy(results, "Invaild Arguments \n");
return results;
}
if(pFile != NULL)
{
while(fgets(results, sizeof(results), pFile) != NULL)
{
//fputs(mystring, fd);
write(fd,results,strlen(results));
}
}
else
{
printf("Invalid File or Address \n");
}
fclose(pFile);
return "End of File \0";
}
Server Code to execute the command
else if(strcmp(command, "get") == 0)
{
int pid = fork();
if (pid ==-1)
{
printf("Failed To Fork...\n");
return-1;
}
if (pid !=0)
{
wait(NULL);
}
else
{
char* temp;
temp = getRequest(buf, newsockfd);
strcpy(buf, temp);
send(newsockfd, buf, sizeof(buf), 0 );
exit(1);
}
}
The whole else if clause in the client code is a bit large for a function, let alone a part of a function as it presumably is. The logic in the code is ... interesting. Let us dissect the first section:
else if (strcmp(commandCopy, get) == 0)
{
char *ptr;
int total = 0;
char *arguments[1024];
char *temp;
ptr = strtok(copy, " ");
while (ptr != NULL)
{
temp = (char *)malloc(sizeof(ptr));
temp = ptr;
arguments[total] = temp;
total++;
ptr = strtok(NULL, " ");
}
I've removed immaterial declarations and some code. The use of strtok() is fine in context, but the memory allocation is leaky. You allocate enough space for a character pointer, and then copy the pointer from strtok() over the only pointer to the allocated space (thus leaking it). Then the pointer is copied to arguments[total]. The code could, therefore, be simplified to:
else if (strcmp(commandCopy, get) == 0)
{
char *ptr;
int total = 0;
char *arguments[1024];
ptr = strtok(copy, " ");
while (ptr != NULL)
{
arguments[total++] = ptr;
ptr = strtok(NULL, " ");
}
Nominally, there should be a check that you don't overflow the arguments list, but since the original limits the string to 2000 characters, you can't have more than 1000 arguments (all single characters separated by single spaces).
What you have works - it achieves the same assignment the long way around, but it leaks memory prodigiously.
The main problem seems to be that the server sends all the contents, but it doesn't close the socket, so the client has no way of knowing the server's done. If you close the socket after you finish sending the data (or just call shutdown()), then the client's read() will return 0 when it finishes reading the data.
FWIW, there are lots of other problems with this code:
getRequest: you call malloc but never free. In fact, the return value is thrown away.
Why bother forking if you're just going to wait() on the child?
You probably want to use strlcpy instead of strpcy to avoid buffer overruns.