Linux n00b here. So about a month ago I installed emacs and the gcc/g++ compiler and have gotten started with programming. I found some code online for an echo server program, copied it and compiled it to test the networking functions. It compiled but then when I tried to run it I got the error message: Segmentation fault(core dumped). When I looked carefully at the debugger details it was an error in the "fwrite()" function. I linked the code to the library libstdc++.a upon compiling and creating the output file so it does make me wonder if there is some critical error in the actual library functions and I need to go back, find the function .c sourcecode, and then add them to the headers to make it work. The code is posted below. Anybody else had this problem?
#include <sys-socket.h> /* socket definitions */
#include <sys-types.h> /* socket types */
#include <netinet-in.h> /* inet (3) functions */
#include <unistd.h> /* misc. UNIX functions */
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <ether.h>
#include <string.h>
/* Global constants */
#define ECHO_PORT 2002
#define MAX_LINE 1000
#define LISTENQ 5
ssize_t Readline(int sockd, char *vptr,size_t maxlen) {
ssize_t n, rc;
char* c;
msghdr* buffer;
buffer->msg_iov->iov_base = vptr;
buffer->msg_iov->iov_len = maxlen;
for ( n = 1; n < maxlen; n++ ) {
if ( (rc = recvmsg(sockd,buffer, 1)) == 1 ) {
c = buffer->msg_iov->iov_base++;
if (*c == '\n' )
break;
}
else if ( rc == 0 ) {
if ( n == 1 )
return 0;
else
break;
}
else {
if (rc < 0 )
continue;
return -1;
}
}
buffer->msg_iov->iov_base = 0;
return n;
}
/* Write a line to a socket */
ssize_t Writeline(int sockd, char *vptr) {
msghdr *buffer;
buffer->msg_iov->iov_base = vptr;
size_t nleft = buffer->msg_iov->iov_len;
ssize_t nwritten;
while ( nleft > 0 ) {
if ( (nwritten = sendmsg(sockd, buffer, nleft)) < 0 ) {
return -1;
}
nleft -= nwritten;
buffer += nwritten;
}
return nwritten;
}
int main(int argc, char *argv[]) {
int list_s; /* listening socket */
int conn_s; /* connection socket */
short int port; /* port number */
struct sockaddr_in servaddr; /* socket address structure */
char *endptr; /* for strtol() */
char buffer[MAX_LINE];
port = 5000;
/* Create the listening socket */
if ( (list_s = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
fprintf(stderr, "ECHOSERV: Error creating listening socket.\n");
exit(EXIT_FAILURE);
}
/* Set all bytes in socket address structure to
zero, and fill in the relevant data members */
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(port);
/* Bind our socket addresss to the
listening socket, and call listen() */
if ( bind(list_s, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0 ) {
fprintf(stderr, "ECHOSERV: Error calling bind()\n");
exit(EXIT_FAILURE);
}
if ( listen(list_s, LISTENQ) < 0 ) {
fprintf(stderr, "ECHOSERV: Error calling listen()\n");
exit(EXIT_FAILURE);
}
/* Enter an infinite loop to respond
to client requests and echo input */
while ( 1 ) {
/* Wait for a connection, then accept() it */
if ( (conn_s = accept(list_s, NULL, NULL) ) < 0 ) {
fprintf(stderr, "ECHOSERV: Error calling accept()\n");
exit(EXIT_FAILURE);
}
/* Retrieve an input line from the connected socket
then simply write it back to the same socket. */
Readline(conn_s, buffer, MAX_LINE-1);
Writeline(conn_s, buffer);
/* Close the connected socket */
if ( shutdown(conn_s,0) < 0 ) {
fprintf(stderr, "ECHOSERV: Error calling close()\n");
exit(EXIT_FAILURE);
}
}
}
ssize_t Writeline(int sockd, char *vptr) {
msghdr *buffer;
buffer->msg_iov->iov_base = vptr;
your pointer buffer is not initialized. You might look at this code snippet to do it correctly:
/* This structure contains parameter information for sendmsg. */
struct msghdr mh;
/* The message header contains parameters for sendmsg. */
mh.msg_name = (caddr_t) &dest;
mh.msg_namelen = sizeof(dest);
mh.msg_iov = iov;
mh.msg_iovlen = 3;
mh.msg_accrights = NULL; /* irrelevant to AF_INET */
mh.msg_accrightslen = 0; /* irrelevant to AF_INET */
rc = sendmsg(s, &mh, 0); /* no flags used */
if (rc == -1) {
perror("sendmsg failed");
return -1;
}
return 0;
}
sendmsg
You are not setting the buffer pointer variables in your Writeline() and ReadLine() functions.
ssize_t Writeline(int sockd, char *vptr) {
msghdr *buffer;
//this is not appropriate as buffer does not point to appropriate memory.
buffer->msg_iov->iov_base = vptr;
size_t nleft = buffer->msg_iov->iov_len;
ssize_t nwritten;
...
return nwritten;
}
Accessing buffer->msg_iov->iov_base or buffer->msg_iov->iov_len or even buffer is not appropriate without allocating it or setting to appropriate memory is not valid.
Did you actually COPY this, or did you copy bits and then paste it together yourself?
It's not very hard to fix at least to the point where it doesn't crash by itself - I didn't get further because my firewall settings are too strict to just fire up a program and use a random port, and I don't feel like messing up my firewall setting just to test your code.
So, as pointed out msghdr *buffer; means that the pointer for buffer is uninitialized. The easy fix is to NOT use a pointer, and instead use the address of buffer when you need it. You then need to have an iov data structure.
So, in receive, you end up with something like this:
msghdr buffer;
iovec iov;
buffer.msg_iov = &iov;
...
if ( (rc = recvmsg(sockd, &buffer, 1)) == 1 ) {
c = vptr++;
buffer.msg_iov->iov_base = vptr;
Note the & in front of buffer. I also changed the next line, as it was doing ++ on a void pointer, which is not clearly defined in C++, so the compiler gave a warning. (There's also a warning for buffer not initialized).
A similar treatment is needed in the `WriteLine function.
iovec iov;
buffer.msg_iov = &iov;
buffer.msg_iov->iov_base = vptr;
size_t nleft = MAX_LINE;
...
if ( (nwritten = sendmsg(sockd, &buffer, nleft)) < 0 ) {
....
nleft -= nwritten;
vptr += nwritten;
buffer.msg_iov->iov_base = vptr;
Again, the increment of iov_base is incrementing a void *, which hasn't been defined since I wrote it above, so need to make sure that the pointer has a different type - reusing vptr is decent here.
As an aside, I changed the nleft to set to MAX_LINE, as you don't pass in the size of the line. I would suggest that you change it so that it does take the size as an argument, similar to the ReadLine function.
Finally, please do yourself a favour and use -Wall -Werror when compiling the code - that means that you will get warnings when you do "silly" things - it may work, but it may also NOT work. Nearly all warnings from the compiler are USEFUL.
Remember when using a pointer in C or C++, you should make sure it points at something. Just writing T* ptr; only gives you a pointer, there is no memory attached to the pointer, so before you USE that pointer, you should assign it in some way.
I'm far from convinced this covers everything - but it should get you somewhat on the way to getting something working.
Related
EDIT1: Per request of John Bollinger, I've included the full client and server code below.
I am sending 4-digit penny prices over a socket connection; e.g., 43.75, 29.43, 94.75, etc. Buffer size is set to 1024 bytes. At the moment, I am converting float prices to c-strings for transmission--not optimal, but I'm working on it. By my calculations, price size is 6 bytes: 4 digits, a decimal point, and the c-string terminating character '\0'.
The problem is that, on the client side, prices are not printed until the 1024-byte buffer is full. I would like each price tick sent and handled as it comes in, and force a buffer flush, and have each tick to be handled separately. In other words, I'd like each price to be sent in a separate packet, and not buffer the 1024 bytes.
How can I force each price tick to be handled separately? Thanks for your help. Sincerely, Keith :^)
The socket connection code is taken from the following url:
http://www.programminglogic.com/example-of-client-server-program-in-c-using-sockets-and-tcp/
Server-side:
char buffer[1024]; // buffer set to 1024
char res[1024] // res contains the a float rounded and converted to a string.
// res is copied into buffer, and then sent with size 6:
// 22.49\0 = 6 characters.
strcpy(buffer, res);
send(newSocket,buffer,6,0);
Client-side:
while(1) {
recv(clientSocket, buffer, 1024, 0);
printf("%s ",buffer);
}
I would expect the prices to print as they arrive, like so:
pickledEgg$ 49.61
pickledEgg$ 50.20
pickledEgg$ 49.97
pickledEgg$ etc..
but 1024 bytes worth of prices are being buffered:
pickledEgg$ 49.61 50.20 49.97 49.86 49.52 50.24 49.79 49.52 49.84 50.29 49.83 49.97 50.34 49.81 49.84 49.50 50.08 50.06 49.54 50.04 50.09 50.08 49.54 50.43 49.97 50.33 50.29 50.08 50.43 50.02 49.86 50.06 50.24 50.33 50.43 50.25 49.58 50.25 49.79 50.43 50.04 49.63 49.88 49.86 49.93 50.22 50.38 50.02 49.79 50.41 49.56 49.88 49.52 49.59 50.34 49.97 49.93 49.63 50.06 50.38 50.15 50.43 49.95 50.40 49.77 50.40 49.68 50.36 50.13 49.95 50.29 50.18 50.09 49.66 50.06 50.04 50.38 49.95 49.56 50.18 49.86 50.13 50.09 49.88 49.74 49.91 49.88 49.70 49.56 50.43 49.58 49.74 49.88 49.54 49.63 50.15 49.97 49.79 49.52 49.59 49.77 50.31 49.81 49.88 50.47 50.36 50.40 49.86 49.81 49.97 49.54 50.18 50.11 50.13 50.08 50.36 50.06 50.45 50.06 50.13 50.38 49.65 49.88 50.29 49.70 50.00 50.45 49.68 50.29 50.47 50.29 50.09 50.27 49.59 50.45 50.24 50.47 49.88 50.11 49.77 49.86 50.16 49.97 50.47 50.31 49.56 49.84 50.38 50.02 50.40 49.52 49.90 50.09 49.90 50.20 49.81 50.38 50.15 49.99 49.70 50.11 49.77 49.79 49.88 49.88 49.75 50.13 50.36 49.63 49.74 50.1
EDIT1: Server-side code:
/****************** SERVER CODE ****************/
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <math.h>
void reverse(char *str, int len)
{
int i=0, j=len-1, temp;
while (i<j)
{
temp = str[i];
str[i] = str[j];
str[j] = temp;
i++; j--;
}
}
int intToStr(int x, char str[], int d)
{
int i = 0;
while (x)
{
str[i++] = (x%10) + '0';
x = x/10;
}
// If number of digits required is more, then
// add 0s at the beginning
while (i < d)
str[i++] = '0';
reverse(str, i);
str[i] = '\0';
return i;
}
void ftoa(float n, char *res, int afterpoint)
{
// Extract integer part
int ipart = (int)n;
// Extract floating part
float fpart = n - (float)ipart;
// convert integer part to string
int i = intToStr(ipart, res, 0);
// check for display option after point
if (afterpoint != 0)
{
res[i] = '.'; // add dot
// Get the value of fraction part upto given no.
// of points after dot. The third parameter is needed
// to handle cases like 233.007
// fpart = fpart * pow(10, afterpoint);
fpart = fpart * 100;
intToStr((int)fpart, res + i + 1, afterpoint);
}
}
float randPrice() {
int b;
float d;
b = 4950 + rand() % 100 + 1;
d = (float)b/100;
return d;
}
void wait() {
int i, j, k;
for (i=0; i<10000; ++i) {
for (j=0; j<10000; ++j) {
k = i + j + i * j;
}
}
}
int main(){
int welcomeSocket, newSocket;
char buffer[1024];
struct sockaddr_in serverAddr;
struct sockaddr_storage serverStorage;
socklen_t addr_size;
char res[1024];
float n;
srand(time(NULL));
/*---- Create the socket. The three arguments are: ----*/
/* 1) Internet domain 2) Stream socket 3) Default protocol (TCP in this case) */
welcomeSocket = socket(PF_INET, SOCK_STREAM, 0);
/*---- Configure settings of the server address struct ----*/
/* Address family = Internet */
serverAddr.sin_family = AF_INET;
/* Set port number, using htons function to use proper byte order */
serverAddr.sin_port = htons(7891);
/* Set IP address to localhost */
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
/* Set all bits of the padding field to 0 */
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
/*---- Bind the address struct to the socket ----*/
bind(welcomeSocket, (struct sockaddr *) &serverAddr, sizeof(serverAddr));
/*---- Listen on the socket, with 5 max connection requests queued ----*/
if(listen(welcomeSocket,5)==0)
printf("Listening\n");
else
printf("Error\n");
/*---- Accept call creates a new socket for the incoming connection ----*/
addr_size = sizeof serverStorage;
newSocket = accept(welcomeSocket, (struct sockaddr *) &serverStorage, &addr_size);
/*---- Send prices to the socket of the incoming connection ----*/
while(1) {
n = randPrice(); // Get a random, float price
ftoa(n, res, 2); // Convert price to string
strcpy(buffer, res); // copy to buffer
send(newSocket,buffer,6,0); // send buffer
wait();
}
return 0;
}
Client-side code:
/****************** CLIENT CODE ****************/
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
void wait() {
int i, j, k;
for (i=0; i<10000; ++i) {
for (j=0; j<10000; ++j) {
k = i + j + i * j;
}
}
}
int main(){
int clientSocket;
char buffer[1024];
struct sockaddr_in serverAddr;
socklen_t addr_size;
/*---- Create the socket. The three arguments are: ----*/
/* 1) Internet domain 2) Stream socket 3) Default protocol (TCP in this case) */
clientSocket = socket(PF_INET, SOCK_STREAM, 0);
/*---- Configure settings of the server address struct ----*/
/* Address family = Internet */
serverAddr.sin_family = AF_INET;
/* Set port number, using htons function to use proper byte order */
serverAddr.sin_port = htons(7891);
/* Set IP address to localhost */
serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
/* Set all bits of the padding field to 0 */
memset(serverAddr.sin_zero, '\0', sizeof serverAddr.sin_zero);
/*---- Connect the socket to the server using the address struct ----*/
addr_size = sizeof serverAddr;
connect(clientSocket, (struct sockaddr *) &serverAddr, addr_size);
/*---- Read the message from the server into the buffer ----*/
int r = 0;
while(1) {
r = recv(clientSocket, buffer, 1024, 0);
printf("recv value: %i\n", r);
printf("%s ",buffer);
wait();
}
return 0;
}
It is recv() that is buffering 1024 bytes.
You have 2 options:
Read character-by-character (buffer size = 1). Inefficient but simple.
Set O_NONBLOCK using fcntl() on client side and use select() to wait till there is data to read and then call recv(). Complex, you could get any number of data or even partial data, but it is going to be efficient.
My apologies for lack of clarity in my comment.
It is impossible to reliably separate data based solely on the packet in which it arrived. Disabling Nagle's Algorithm with TCP_NODELAY may greatly improve the likelihood of getting the desired behaviour but nothing can guarantee it.
For example:
Message A is written and sent immediately
Message B is written and sent immediately
Message A is delayed on the network (too many possible reasons to list)
Message B arrives at receiver
Message A arrives at receiver
Receiver makes Messages A and B available
recv will read everything from the buffer, Message A and Message B, up to the maximum number of bytes requested. Without some method of telling Message A from Message B, you cannot proceed.
OK, but you know the length of Message A and Message B, 6 bytes, so you simply recv 6 bytes. Right?
Almost. For a number of reasons, the sender may not be able to send the whole message in one packet and a recv for 6 bytes only returns, say, 2.
The only way to be sure, other than nuking the site from orbit, is to loop on recv until all 6 bytes have been read.
bool receiveAll(int sock,
char * bufp,
size_t len)
{
int result;
size_t offset = 0;
while (len > 0)
{ // loop until we have all of our data
result = recv(sock, &bufp[offset], len, 0);
if (result < 0)
{ // Socket is in a bad state
// handle error
return false;
}
else if (result == 0)
{ // socket closed
return false;
}
len -= result;
offset += result;
}
return true;
}
Usage:
while(receiveAll(clientSocket, buffer 6)) {
printf("%s ",buffer);
}
This will keep looping until the socket is closed or an error forces the loop to exit. No waiting is required, recv waits for you.
What it doesn't have is a good mechanism for a polite shutdown of the client while the server is still running.
This allows the sender to remain stupid. Otherwise the sender needs to do something similar making sure that it only ever sends full messages, and no messages ever straddle multiple packets. This is significantly more effort to get right than the loop in the receiveAll function. See Akash Rawal's answer for hints on how to do this.
I googled a lot and didn't get an answer, hence posting it here.
In the following C program(the server code) I want a Unix domain socket server that's listening at /tmp/unix-test-socket. My problem is that the client code is sucessfully able to connect to the server. However, once its connected and I have "accepted" the connection, the select call does NOT block.
So let me explain.
Initially the unix_domain_socket = 3
As soon as I get the first request, accept the connection and, store it in unix_domain_socket_connections[max_unix_domain_socket_connections]. The value of the socket fd is 4.
When I run the server code goes into a loop because the select call believes that always there is data in socket 4.
I run the CLIENT side as:
./unix-client "/tmp/unix-test-socket" SEND_DATA
Output from the SERVER side:
Client sent us a message!
Successfully accepted the new ION connection with fd 4!
[program_select_to_look_at_right_sockets]: Storing fd 4
Data Arrived on UNIX domain socket 4
length 10 SEND_DATA <-- I get the data sent by the client
[program_select_to_look_at_right_sockets]: Storing fd 4 *<-- Why isnt select blocking and why does it think there is still data on socket 4*
Data Arrived on UNIX domain socket 4
[program_select_to_look_at_right_sockets]: Storing fd 4
Data Arrived on UNIX domain socket 4
SERVER CODE:
int unix_domain_socket = 0;
int max_unix_domain_socket_connections;
int unix_domain_socket_connections[2];
char *unix_domain_socket_name = "/tmp/unix-test-socket";
int open_unix_domain_server()
{
int socket_fd, result;
struct sockaddr_un name;
int client_sent_quit_message;
socklen_t socket_length;
max_unix_domain_socket_connections = 0;
memset((void *) &name, 0, sizeof(name));
socket_fd = socket(AF_LOCAL, SOCK_STREAM, 0);
name.sun_family = AF_UNIX;
strcpy(name.sun_path, unix_domain_socket_name);
socket_length = strlen(name.sun_path) + sizeof(name.sun_family);
/* Remove this socket if it already exists */
unlink(name.sun_path);
result = bind(socket_fd, (struct sockaddr *) &name, socket_length);
if (result < 0)
goto Error;
result = listen(socket_fd, MAX_UNIX_DOMAIN_SOCKETS);
return socket_fd;
Error:
printf("[%s] Error in either listen or bind!\n", __FUNCTION__);
return -1;
}
int accept_new_unix_domain_connection()
{
int client_fd;
struct sockaddr_un new_connection;
socklen_t new_conn_length = sizeof(new_connection);
memset((void *) &new_connection, 0, sizeof(new_connection));
client_fd = accept(unix_domain_socket, (struct sockaddr *) &new_connection,
&new_conn_length);
if (client_fd < 0)
{
printf("The following error occurred accept failed %d %d\n", errno,
unix_domain_socket);
}
unix_domain_socket_connections[max_unix_domain_socket_connections] =
client_fd;
max_unix_domain_socket_connections++;
return client_fd;
}
int check_if_new_client_is_unix_domain(fd_set readfds)
{
int unix_fd = 0;
for (unix_fd = 0; unix_fd < 2; unix_fd++)
{
if (FD_ISSET(unix_domain_socket_connections[unix_fd], &readfds))
{
printf("Data Arrived on UNIX domain socket %d\n",
unix_domain_socket_connections[unix_fd]);
return 1;
}
}
return 0;
}
int process_data_on_unix_domain_socket(int unix_socket)
{
int length = 0;
char* data_from_gridFtp;
/* First, read the length of the text message from the socket. If
read returns zero, the client closed the connection. */
if (read(unix_socket, &length, sizeof(length)) == 0)
return 0;
/* Allocate a buffer to hold the text. */
data_from_gridFtp = (char*) malloc(length + 1);
/* Read the text itself, and print it. */
recv(unix_socket, data_from_gridFtp, length, 0);
printf("length %d %s\n", length, data_from_gridFtp);
return length;
}
void program_select_to_look_at_right_sockets(fd_set *readfds, int *maxfds)
{
int unix_fd = 0;
FD_ZERO(readfds);
FD_SET(unix_domain_socket, readfds);
for (unix_fd = 0; unix_fd < 2; unix_fd++)
{
if (unix_domain_socket_connections[unix_fd])
{
printf("[%s]: Storing fd %d\n", __FUNCTION__,
unix_domain_socket_connections[unix_fd]);
FD_SET(unix_domain_socket_connections[unix_fd], readfds);
if (*maxfds < unix_domain_socket_connections[unix_fd])
*maxfds = unix_domain_socket_connections[unix_fd];
}
}
}
int main(int argc, char**argv)
{
int result, maxfds, clientfd, loop;
fd_set readfds;
int activity;
socklen_t client_len;
struct sockaddr_in client_address;
FD_ZERO(&readfds);
unix_domain_socket = open_unix_domain_server();
if (unix_domain_socket < 0)
return -1;
maxfds = unix_domain_socket;
FD_SET(unix_domain_socket, &readfds);
for (loop = 0; loop < 4; loop++)
{
program_select_to_look_at_right_sockets(&readfds, &maxfds);
activity = select(maxfds + 1, &readfds, NULL, NULL, NULL);
if (FD_ISSET(unix_domain_socket, &readfds))
{
printf("client sent us a message!\n");
clientfd = accept_new_unix_domain_connection();
if (clientfd < 0)
break;
}
else if (check_if_new_client_is_unix_domain(readfds))
{
process_data_on_unix_domain_socket(clientfd);
}
}
}
CLIENT CODE:
/* Write TEXT to the socket given by file descriptor SOCKET_FD. */
void write_text(int socket_fd, const char* text)
{
/* Write the number of bytes in the string, including
NUL-termination. */
int length = strlen(text) + 1;
send(socket_fd, &length, sizeof(length), 0);
/* Write the string. */
send(socket_fd, text, length, 0);
}
int main(int argc, char* const argv[])
{
const char* const socket_name = argv[1];
const char* const message = argv[2];
int socket_fd;
struct sockaddr_un name;
/* Create the socket. */
socket_fd = socket(PF_LOCAL, SOCK_STREAM, 0);
/* Store the server’s name in the socket address. */
name.sun_family = AF_UNIX;
strcpy(name.sun_path, socket_name);
/* Connect the socket. */
connect(socket_fd, (struct sockaddr *) &name, SUN_LEN(&name));
/* Write the text on the command line to the socket. */
write_text(socket_fd, message);
close(socket_fd);
return 0;
}
You will find that select() will return "ready for reading" if the far end has closed... The rule for "ready for reading" is that it is true iff a read() would not block. read() does not block if it returns 0.
According to the select linux man pages there is a bug related to this behaviour:
Under Linux, select() may report a socket file descriptor as "ready for reading", while nevertheless a subsequent read blocks. This could for example happen when data has arrived but upon examination has wrong checksum and is discarded. There may be other circumstances in which a file descriptor is spuriously reported as ready.
On the other hand, I recommend you to consider the strategy for handle activity and process data into the loop(irrelevant parts removed):
for (loop = 0; loop<4; loop++)
{
// ...
activity = select( maxfds + 1 , &readfds , NULL , NULL , NULL);
// ...
}
This will block for the first sockect while the 2nd, 3th, and fourth might be ready. At least use a timeout and check errno for handle timeout event. See select man pages for more info.
I'm trying to learn how to use libnetfilter_queue. I've compiled the example provided with the library.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <linux/types.h>
#include <linux/netfilter.h> /* for NF_ACCEPT */
#include <libnetfilter_queue/libnetfilter_queue.h>
/* returns packet id */
static u_int32_t print_pkt (struct nfq_data *tb)
{
int id = 0;
struct nfqnl_msg_packet_hdr *ph;
struct nfqnl_msg_packet_hw *hwph;
u_int32_t mark,ifi;
int ret;
char *data;
ph = nfq_get_msg_packet_hdr(tb);
if (ph) {
id = ntohl(ph->packet_id);
printf("hw_protocol=0x%04x hook=%u id=%u ",
ntohs(ph->hw_protocol), ph->hook, id);
}
hwph = nfq_get_packet_hw(tb);
if (hwph) {
int i, hlen = ntohs(hwph->hw_addrlen);
printf("hw_src_addr=");
for (i = 0; i < hlen-1; i++)
printf("%02x:", hwph->hw_addr[i]);
printf("%02x ", hwph->hw_addr[hlen-1]);
}
mark = nfq_get_nfmark(tb);
if (mark)
printf("mark=%u ", mark);
ifi = nfq_get_indev(tb);
if (ifi)
printf("indev=%u ", ifi);
ifi = nfq_get_outdev(tb);
if (ifi)
printf("outdev=%u ", ifi);
ifi = nfq_get_physindev(tb);
if (ifi)
printf("physindev=%u ", ifi);
ifi = nfq_get_physoutdev(tb);
if (ifi)
printf("physoutdev=%u ", ifi);
ret = nfq_get_payload(tb, &data);
if (ret >= 0)
printf("payload_len=%d ", ret);
fputc('\n', stdout);
return id;
}
static int cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,
struct nfq_data *nfa, void *data)
{
u_int32_t id = print_pkt(nfa);
printf("entering callback\n");
return nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL);
}
int main(int argc, char **argv)
{
struct nfq_handle *h;
struct nfq_q_handle *qh;
int fd;
int rv;
char buf[4096] __attribute__ ((aligned));
printf("opening library handle\n");
h = nfq_open();
if (!h) {
fprintf(stderr, "error during nfq_open()\n");
exit(1);
}
printf("unbinding existing nf_queue handler for AF_INET (if any)\n");
if (nfq_unbind_pf(h, AF_INET) < 0) {
fprintf(stderr, "error during nfq_unbind_pf()\n");
exit(1);
}
printf("binding nfnetlink_queue as nf_queue handler for AF_INET\n");
if (nfq_bind_pf(h, AF_INET) < 0) {
fprintf(stderr, "error during nfq_bind_pf()\n");
exit(1);
}
printf("binding this socket to queue '0'\n");
qh = nfq_create_queue(h, 1, &cb, NULL);
if (!qh) {
fprintf(stderr, "error during nfq_create_queue()\n");
exit(1);
}
printf("setting copy_packet mode\n");
if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) {
fprintf(stderr, "can't set packet_copy mode\n");
exit(1);
}
fd = nfq_fd(h);
while ((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0) {
printf("pkt received\n");
nfq_handle_packet(h, buf, rv);
}
printf("unbinding from queue 0\n");
nfq_destroy_queue(qh);
#ifdef INSANE
/* normally, applications SHOULD NOT issue this command, since
* it detaches other programs/sockets from AF_INET, too ! */
printf("unbinding from AF_INET\n");
nfq_unbind_pf(h, AF_INET);
#endif
printf("closing library handle\n");
nfq_close(h);
exit(0);
}
Launching the executable it doesn't receive anything.
I also followed this thread and tried to use netcat to generate traffic but again i didn't see any packet
Maybe I'm missing something to really interact with filter queues?
Yes, you have. If your firewall lets the packets trough the rules nothing will happen and the packets wont left the kernel space. But if you setting up some rules that send the packets to the user space, your programm will work.
iptables -A INPUT -i eth0 -j NFQUEUE --queue-num 0
This line will send all packets from the INPUT with the --in-interface eth0 into the userspace.
libnetfilter_queue is as it's named, a filter. That means, it filters out traffic based on the settings you give it when you create and open the queue.
If you do not send any traffic through this filter, the filter has nothing to work on. How much (what kind of) traffic that goes through this filter, you must set in iptable.
Iptable works as a firewall into, through or out of your system. Libnetfilter_queue lets you control what to do with the filtered traffic.
Hope this helps you somewhat.
Reading that thread I found I haven't added iptables rules... Adding those rules make the trick.
So I always need to set iptables rules to get packets using netfilter library?
I have been trying to send packets using raw socket in following code.This code I found somewhere in the internet. I created my own ipheader and udp header. The whole data packet is sent using sendto() function on raw socket. sendto() returns 0. Which means a packet of 0 length is sent out of it and hence even wireshark doesnt detect any packet. Where is my mistake?
// Must be run by root lol! Just datagram, no payload/data
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <cstdlib>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
// The packet length
#define PCKT_LEN 35
// Can create separate header file (.h) for all headers' structure
// The IP header's structure
struct ipheader {
unsigned char iph_ihl:4, iph_ver:4;
unsigned char iph_tos;
unsigned short int iph_len;
unsigned short int iph_ident;
unsigned char iph_flag;
unsigned short int iph_offset;
unsigned char iph_ttl;
unsigned char iph_protocol;
unsigned short int iph_chksum;
unsigned int iph_sourceip;
unsigned int iph_destip;
};
// UDP header's structure
struct udpheader {
unsigned short int udph_srcport;
unsigned short int udph_destport;
unsigned short int udph_len;
unsigned short int udph_chksum;
};
// total udp header length: 8 bytes (=64 bits)
// Function for checksum calculation. From the RFC,
// the checksum algorithm is:
// "The checksum field is the 16 bit one's complement of the one's
// complement sum of all 16 bit words in the header. For purposes of
// computing the checksum, the value of the checksum field is zero."
unsigned short csum(unsigned short *buf, int nwords)
{ //
unsigned long sum;
for(sum=0; nwords>0; nwords--)
sum += *buf++;
sum = (sum >> 16) + (sum &0xffff);
sum += (sum >> 16);
return (unsigned short)(~sum);
}
// Source IP, source port, target IP, target port from the command line arguments
int main(int argc, char *argv[])
{
int sd;
// No data/payload just datagram
char buffer[PCKT_LEN];
// Our own headers' structures
struct ipheader *ip = (struct ipheader *) buffer;
struct udpheader *udp = (struct udpheader *) (buffer + sizeof(struct ipheader));
// Source and destination addresses: IP and port
struct sockaddr_in sin, din;
int one = 1;
const int *val = &one;
memset(buffer, 0, PCKT_LEN);
if(argc != 5)
{
printf("- Invalid parameters!!!\n");
printf("- Usage %s <source hostname/IP> <source port> <target hostname/IP> <target port>\n", argv[0]);
exit(-1);
}
// Create a raw socket with UDP protocol
sd = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);
if(sd < 0)
{
perror("socket() error");
// If something wrong just exit
exit(-1);
}
else
printf("socket() - Using SOCK_RAW socket and UDP protocol is OK.\n");
// The source is redundant, may be used later if needed
// The address family
sin.sin_family = AF_INET;
din.sin_family = AF_INET;
// Port numbers
sin.sin_port = htons(atoi(argv[2]));
din.sin_port = htons(atoi(argv[4]));
// IP addresses
sin.sin_addr.s_addr = inet_addr(argv[1]);
din.sin_addr.s_addr = inet_addr(argv[3]);
// Fabricate the IP header or we can use the
// standard header structures but assign our own values.
ip->iph_ihl = 5;
ip->iph_ver = 4;
ip->iph_tos = 16; // Low delay
ip->iph_len = sizeof(struct ipheader) + sizeof(struct udpheader);
ip->iph_ident = htons(54321);
ip->iph_ttl = 64; // hops
ip->iph_protocol = 17; // UDP
// Source IP address, can use spoofed address here!!!
ip->iph_sourceip = inet_addr(argv[1]);
// The destination IP address
ip->iph_destip = inet_addr(argv[3]);
// Fabricate the UDP header. Source port number, redundant
udp->udph_srcport = htons(atoi(argv[2]));
// Destination port number
udp->udph_destport = htons(atoi(argv[4]));
udp->udph_len = htons(sizeof(struct udpheader));
// Calculate the checksum for integrity
ip->iph_chksum = csum((unsigned short *)buffer, sizeof(struct ipheader) + sizeof(struct udpheader));
// Inform the kernel do not fill up the packet structure. we will build our own...
if(setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0)
{
perror("setsockopt() error");
exit(-1);
}
else
printf("setsockopt() is OK.\n");
// Send loop, send for every 2 second for 100 count
printf("Trying...\n");
printf("Using raw socket and UDP protocol\n");
printf("Using Source IP: %s port: %u, Target IP: %s port: %u.\n", argv[1], atoi(argv[2]), argv[3], atoi(argv[4]));
int count;
int i;
for(count = 1; count <=20; count++)
{
if(i = sendto(sd, buffer, PCKT_LEN, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
// Verify
{
perror("sendto() error");
exit(-1);
}
else
{
printf("Count #%u - sendto() is OK. Data Length#%d\n", count,i);
sleep(2);
}
}
close(sd);
return 0;
}
Aha! I've got at least part of it.
i = sendto(sd, buffer, PCKT_LEN, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0
is the same as
i = (sendto(sd, buffer, PCKT_LEN, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
you probably want:
(i = sendto(sd, buffer, PCKT_LEN, 0, (struct sockaddr *)&sin, sizeof(sin))) < 0
You may want to:
Turn on warnings in your compiler - at least if you use gcc, that should give you a warning for comparing and assigning in the same if-statement.
Retry with the fixed code.
I'm sure there may be other problems in your code too - I'm no network expert.
It is really hard to read this piece of code and to understand what and why you're doing. So I can recoomend you look at my piece of code: dhcp client implementation
Look at function getSock() to see how socket is created, and on function talker() on how to form and send completed packet.
Local IP header structure is wrong... my suggestion is to include the IP header provided with your distro (are you using linux? don't you?).
What i did is just include linux/ip.h, rename ipheader structure reference to iphdr, and rename the ip header fields according to the structure described in the latter file.
I tried to sniff packets with tcpdump and it works now (i didn't try with wireshark but it must work too)
Try this fixed code:
// Must be run by root lol! Just datagram, no payload/data
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/udp.h>
#include <linux/ip.h>
// The packet length
#define PCKT_LEN 35
// UDP header's structure
struct udpheader {
unsigned short int udph_srcport;
unsigned short int udph_destport;
unsigned short int udph_len;
unsigned short int udph_chksum;
};
// total udp header length: 8 bytes (=64 bits)
// Function for checksum calculation. From the RFC,
// the checksum algorithm is:
// "The checksum field is the 16 bit one's complement of the one's
// complement sum of all 16 bit words in the header. For purposes of
// computing the checksum, the value of the checksum field is zero."
unsigned short csum(unsigned short *buf, int nwords)
{ //
unsigned long sum;
for(sum=0; nwords>0; nwords--)
sum += *buf++;
sum = (sum >> 16) + (sum &0xffff);
sum += (sum >> 16);
return (unsigned short)(~sum);
}
// Source IP, source port, target IP, target port from the command line arguments
int main(int argc, char *argv[])
{
int sd;
// No data/payload just datagram
char buffer[PCKT_LEN];
// Our own headers' structures
struct iphdr *ip = (struct iphdr *) buffer;
struct udpheader *udp = (struct udpheader *) (buffer + sizeof(struct iphdr));
// Source and destination addresses: IP and port
struct sockaddr_in sin, din;
int one = 1;
const int *val = &one;
memset(buffer, 0, PCKT_LEN);
if(argc != 5)
{
printf("- Invalid parameters!!!\n");
printf("- Usage %s <source hostname/IP> <source port> <target hostname/IP> <target port>\n", argv[0]);
exit(-1);
}
// Create a raw socket with UDP protocol
sd = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);
if(sd < 0)
{
perror("socket() error");
// If something wrong just exit
exit(-1);
}
else
printf("socket() - Using SOCK_RAW socket and UDP protocol is OK.\n");
// The source is redundant, may be used later if needed
// The address family
sin.sin_family = AF_INET;
din.sin_family = AF_INET;
// Port numbers
sin.sin_port = htons(atoi(argv[2]));
din.sin_port = htons(atoi(argv[4]));
// IP addresses
sin.sin_addr.s_addr = inet_addr(argv[1]);
din.sin_addr.s_addr = inet_addr(argv[3]);
// Fabricate the IP header or we can use the
// standard header structures but assign our own values.
ip->ihl = 5;
ip->version = 4;
ip->tos = 16; // Low delay
ip->tot_len = sizeof(struct iphdr) + sizeof(struct udpheader);
ip->id = htons(54321);
ip->ttl = 64; // hops
ip->protocol = 17; // UDP
// Source IP address, can use spoofed address here!!!
ip->saddr = inet_addr(argv[1]);
// The destination IP address
ip->daddr = inet_addr(argv[3]);
// Fabricate the UDP header. Source port number, redundant
udp->udph_srcport = htons(atoi(argv[2]));
// Destination port number
udp->udph_destport = htons(atoi(argv[4]));
udp->udph_len = htons(sizeof(struct udpheader));
// Calculate the checksum for integrity
ip->check = csum((unsigned short *)buffer, sizeof(struct iphdr) + sizeof(struct udpheader));
// Inform the kernel do not fill up the packet structure. we will build our own...
if(setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0)
{
perror("setsockopt() error");
exit(-1);
}
else
printf("setsockopt() is OK.\n");
// Send loop, send for every 2 second for 100 count
printf("Trying...\n");
printf("Using raw socket and UDP protocol\n");
printf("Using Source IP: %s port: %u, Target IP: %s port: %u.\n", argv[1], atoi(argv[2]), argv[3], atoi(argv[4]));
int count;
int i;
for(count = 1; count <=20; count++)
{
if((i = sendto(sd, buffer, PCKT_LEN, 0, (struct sockaddr *)&sin, sizeof(sin))) < 0)
// Verify
{
perror("sendto() error");
exit(-1);
}
else
{
printf("Count #%u - sendto() is OK. Data Length# %d\n", count,i);
sleep(2);
}
}
close(sd);
return 0;
}
I'm guessing you based that on this example code, which has multiple fatal bugs. It has wasted many hours of my life.
But to answer this specific question (and to help anyone else who is unfortunate enough to try to use that code), the bug that prevents you from seeing the packets in wireshark is here:
sin.sin_addr.s_addr = inet_addr(argv[1]);
This sets the address used for sending the packet in sentdo() to the source address. Therefore, the packet is sent over the loopback interface, and it goes nowhere. (Wireshark or other capture tools will be able to see the packet if you capture the lo/loopback interface, fwiw.)
So the corrected line for this particular program is:
sin.sin_addr.s_addr = inet_addr(argv[3]);
I would like to implement a client-server architecture running on Linux using sockets and C/C++ language that is capable of sending and receiving files. Is there any library that makes this task easy? Could anyone please provide an example?
The most portable solution is just to read the file in chunks, and then write the data out to the socket, in a loop (and likewise, the other way around when receiving the file). You allocate a buffer, read into that buffer, and write from that buffer into your socket (you could also use send and recv, which are socket-specific ways of writing and reading data). The outline would look something like this:
while (1) {
// Read data into buffer. We may not have enough to fill up buffer, so we
// store how many bytes were actually read in bytes_read.
int bytes_read = read(input_file, buffer, sizeof(buffer));
if (bytes_read == 0) // We're done reading from the file
break;
if (bytes_read < 0) {
// handle errors
}
// You need a loop for the write, because not all of the data may be written
// in one call; write will return how many bytes were written. p keeps
// track of where in the buffer we are, while we decrement bytes_read
// to keep track of how many bytes are left to write.
void *p = buffer;
while (bytes_read > 0) {
int bytes_written = write(output_socket, p, bytes_read);
if (bytes_written <= 0) {
// handle errors
}
bytes_read -= bytes_written;
p += bytes_written;
}
}
Make sure to read the documentation for read and write carefully, especially when handling errors. Some of the error codes mean that you should just try again, for instance just looping again with a continue statement, while others mean something is broken and you need to stop.
For sending the file to a socket, there is a system call, sendfile that does just what you want. It tells the kernel to send a file from one file descriptor to another, and then the kernel can take care of the rest. There is a caveat that the source file descriptor must support mmap (as in, be an actual file, not a socket), and the destination must be a socket (so you can't use it to copy files, or send data directly from one socket to another); it is designed to support the usage you describe, of sending a file to a socket. It doesn't help with receiving the file, however; you would need to do the loop yourself for that. I cannot tell you why there is a sendfile call but no analogous recvfile.
Beware that sendfile is Linux specific; it is not portable to other systems. Other systems frequently have their own version of sendfile, but the exact interface may vary (FreeBSD, Mac OS X, Solaris).
In Linux 2.6.17, the splice system call was introduced, and as of 2.6.23 is used internally to implement sendfile. splice is a more general purpose API than sendfile. For a good description of splice and tee, see the rather good explanation from Linus himself. He points out how using splice is basically just like the loop above, using read and write, except that the buffer is in the kernel, so the data doesn't have to transferred between the kernel and user space, or may not even ever pass through the CPU (known as "zero-copy I/O").
Do aman 2 sendfile. You only need to open the source file on the client and destination file on the server, then call sendfile and the kernel will chop and move the data.
Minimal runnable POSIX read + write example
Usage:
get two computers on a LAN.
For example, this will work if both computers are connected to your home router in most cases, which is how I tested it.
On the server computer:
Find the server local IP with ifconfig, e.g. 192.168.0.10
Run:
./server output.tmp 12345
On the client computer:
printf 'ab\ncd\n' > input.tmp
./client input.tmp 192.168.0.10 12345
Outcome: a file output.tmp is created on the sever computer containing 'ab\ncd\n'!
server.c
/*
Receive a file over a socket.
Saves it to output.tmp by default.
Interface:
./executable [<output_file> [<port>]]
Defaults:
- output_file: output.tmp
- port: 12345
*/
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h> /* getprotobyname */
#include <netinet/in.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <unistd.h>
int main(int argc, char **argv) {
char *file_path = "output.tmp";
char buffer[BUFSIZ];
char protoname[] = "tcp";
int client_sockfd;
int enable = 1;
int filefd;
int i;
int server_sockfd;
socklen_t client_len;
ssize_t read_return;
struct protoent *protoent;
struct sockaddr_in client_address, server_address;
unsigned short server_port = 12345u;
if (argc > 1) {
file_path = argv[1];
if (argc > 2) {
server_port = strtol(argv[2], NULL, 10);
}
}
/* Create a socket and listen to it.. */
protoent = getprotobyname(protoname);
if (protoent == NULL) {
perror("getprotobyname");
exit(EXIT_FAILURE);
}
server_sockfd = socket(
AF_INET,
SOCK_STREAM,
protoent->p_proto
);
if (server_sockfd == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
if (setsockopt(server_sockfd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)) < 0) {
perror("setsockopt(SO_REUSEADDR) failed");
exit(EXIT_FAILURE);
}
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(server_port);
if (bind(
server_sockfd,
(struct sockaddr*)&server_address,
sizeof(server_address)
) == -1
) {
perror("bind");
exit(EXIT_FAILURE);
}
if (listen(server_sockfd, 5) == -1) {
perror("listen");
exit(EXIT_FAILURE);
}
fprintf(stderr, "listening on port %d\n", server_port);
while (1) {
client_len = sizeof(client_address);
puts("waiting for client");
client_sockfd = accept(
server_sockfd,
(struct sockaddr*)&client_address,
&client_len
);
filefd = open(file_path,
O_WRONLY | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR);
if (filefd == -1) {
perror("open");
exit(EXIT_FAILURE);
}
do {
read_return = read(client_sockfd, buffer, BUFSIZ);
if (read_return == -1) {
perror("read");
exit(EXIT_FAILURE);
}
if (write(filefd, buffer, read_return) == -1) {
perror("write");
exit(EXIT_FAILURE);
}
} while (read_return > 0);
close(filefd);
close(client_sockfd);
}
return EXIT_SUCCESS;
}
client.c
/*
Send a file over a socket.
Interface:
./executable [<input_path> [<sever_hostname> [<port>]]]
Defaults:
- input_path: input.tmp
- server_hostname: 127.0.0.1
- port: 12345
*/
#define _XOPEN_SOURCE 700
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h> /* getprotobyname */
#include <netinet/in.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <unistd.h>
int main(int argc, char **argv) {
char protoname[] = "tcp";
struct protoent *protoent;
char *file_path = "input.tmp";
char *server_hostname = "127.0.0.1";
char *server_reply = NULL;
char *user_input = NULL;
char buffer[BUFSIZ];
in_addr_t in_addr;
in_addr_t server_addr;
int filefd;
int sockfd;
ssize_t i;
ssize_t read_return;
struct hostent *hostent;
struct sockaddr_in sockaddr_in;
unsigned short server_port = 12345;
if (argc > 1) {
file_path = argv[1];
if (argc > 2) {
server_hostname = argv[2];
if (argc > 3) {
server_port = strtol(argv[3], NULL, 10);
}
}
}
filefd = open(file_path, O_RDONLY);
if (filefd == -1) {
perror("open");
exit(EXIT_FAILURE);
}
/* Get socket. */
protoent = getprotobyname(protoname);
if (protoent == NULL) {
perror("getprotobyname");
exit(EXIT_FAILURE);
}
sockfd = socket(AF_INET, SOCK_STREAM, protoent->p_proto);
if (sockfd == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
/* Prepare sockaddr_in. */
hostent = gethostbyname(server_hostname);
if (hostent == NULL) {
fprintf(stderr, "error: gethostbyname(\"%s\")\n", server_hostname);
exit(EXIT_FAILURE);
}
in_addr = inet_addr(inet_ntoa(*(struct in_addr*)*(hostent->h_addr_list)));
if (in_addr == (in_addr_t)-1) {
fprintf(stderr, "error: inet_addr(\"%s\")\n", *(hostent->h_addr_list));
exit(EXIT_FAILURE);
}
sockaddr_in.sin_addr.s_addr = in_addr;
sockaddr_in.sin_family = AF_INET;
sockaddr_in.sin_port = htons(server_port);
/* Do the actual connection. */
if (connect(sockfd, (struct sockaddr*)&sockaddr_in, sizeof(sockaddr_in)) == -1) {
perror("connect");
return EXIT_FAILURE;
}
while (1) {
read_return = read(filefd, buffer, BUFSIZ);
if (read_return == 0)
break;
if (read_return == -1) {
perror("read");
exit(EXIT_FAILURE);
}
/* TODO use write loop: https://stackoverflow.com/questions/24259640/writing-a-full-buffer-using-write-system-call */
if (write(sockfd, buffer, read_return) == -1) {
perror("write");
exit(EXIT_FAILURE);
}
}
free(user_input);
free(server_reply);
close(filefd);
exit(EXIT_SUCCESS);
}
GitHub upstream.
Further comments
Possible improvements:
Currently output.tmp gets overwritten each time a send is done.
This begs for the creation of a simple protocol that allows to pass a filename so that multiple files can be uploaded, e.g.: filename up to the first newline character, max filename 256 chars, and the rest until socket closure are the contents. Of course, that would require sanitation to avoid a path transversal vulnerability.
Alternatively, we could make a server that hashes the files to find filenames, and keeps a map from original paths to hashes on disk (on a database).
Only one client can connect at a time.
This is specially harmful if there are slow clients whose connections last for a long time: the slow connection halts everyone down.
One way to work around that is to fork a process / thread for each accept, start listening again immediately, and use file lock synchronization on the files.
Add timeouts, and close clients if they take too long. Or else it would be easy to do a DoS.
poll or select are some options: How to implement a timeout in read function call?
A simple HTTP wget implementation is shown at: How to make an HTTP get request in C without libcurl?
Tested on Ubuntu 15.10.
This file will serve you as a good sendfile example : http://tldp.org/LDP/LGNET/91/misc/tranter/server.c.txt