turbulencetoo
turbulencetoo

Reputation: 3701

How to send formatted string to socket using a small buffer?

I am trying to write some xml data to a socket in C. I can print the xml string to the screen using:

printf("<tag1>%d</tag1>"
       "<tag2>%s</tag2>"
       "<tag3>%s</tag3>"
       "<tag4>%d</tag4>",
       int1,
       str2,
       str3,
       int4);

Instead of printing to stdout, I try to snprintf that string to a buffer (char[]), then write the buffer's contents to a socket. Unfortunately, I imagine that here the buffer could be full during the write of either str2 or str3 and perhaps not even big enough to contain either string.

Using snprintf it is easy to check whether I was able to write all the data to the buffer, but not easy to continue where I left off after sending buffer contents to a socket.

Basically: Is there functionality that would let me send, say, 64 bytes at a time of "%d%s%s%d" to a socket, should the formatted string be longer than 64 bytes?

If this functionality does not exist I'm interested in what workarounds you'd suggest (If it helps, you can assume the %s fields are populated by an evil robot that tries to overflow your buffer, regardless of size).

Upvotes: 3

Views: 3091

Answers (2)

On Linux at least with GNU libc you could use asprintf(3) (which gives a malloc-ed string) or dprintf(3) (which prints into a file descriptor).

You could also (and more portably) fdopen(3) the socket file descriptor then fprintf(3) and fflush(3) it. You could configure buffering with setvbuf(3).

fileno(3) is quite useful too...

BTW, snprintf(3) is returning the number of needed bytes. So you might code

char tinybuf[100];
char* buf = tinybuf;
int nbytes= snprintf(tinybuf, sizeof(tinybuf), 
                     "<tag at='%d'>%s</tag>", num, string);
if (nbytes >= sizeof(tinybuf)) { // rarely happens
    char *buf = malloc(nbytes+1);
    if (!buf) { perror("malloc"); abort(); };
    snprintf(buf, nbytes+1, 
             "<tag at='%d'>%s</tag>", num, string);
};
int off=0;
while (nbytes>0) {
   int nbw=write(sock, buf+off, nbytes); 
   if (nbw>0) { off += nbw; nbytes -= nbw; };
   else if (nbw<0 && errno != EINTR) { perror("write"); abort(); };
};
if (buf != tinybuf) free(buf);

This would avoid malloc and free in the common case that tinybuf fits...

Upvotes: 4

Paulo Bu
Paulo Bu

Reputation: 29804

What about using fprintf with a socket descriptor?

Something like:

int sockfd = socket(AF_INET, SOCK_STREAM, 0);
FILE *fd = fdopen(sockfd, "w")
fprintf(fd, "<tag1>%d</tag1>"
   "<tag2>%s</tag2>"
   "<tag3>%s</tag3>"
   "<tag4>%d</tag4>",
   int1,
   str2,
   str3,
   int4);
fflush(fd);

Upvotes: 3

Related Questions