An array of structs defined in other source file - c

For a school project i made this program where clients (a tcpsock_t) can make a TCP connection with a server and pass data through it. I poll the different connections to see if there is data to read.
I got a tcpsock.c with functions for the TCP sockets which is used as library, a connmgr.c as server and a client code (which is not relevant).
In the tcpsock.h i typedef the struct of the tcpsock_t
(other functions below)
typedef struct tcpsock tcpsock_t;
and in the tcpsock.c i declare the struct (and it should stay here, i can not put it in de .h file)
struct tcpsock{
long cookie;
int sd;
char * ip_addr;
int port;
};
In the connmgr.c i want to make an array of this tcpsock_t to store all my connected clients, but when i compile it gives always the same sort of errors:
error: invalid use of undefined type ‘struct tcpsock’
client[conn_counter] = *requestclient;
Can someone tell me what i'm doing wrong?
Thanks a lot!
Here is my server code :
#include "tcpsock.h"
#include "connmgr.h"
int conn_counter = 0;
void add_client(tcpsock_t *newclient, tcpsock_t * array){
conn_counter++;
array= realloc(test,sizeof(get_size_tcpsock())*conn_counter);
array[conn_counter-1]=*newclient; //here i have the error
}
void add_poll(struct pollfd * polllist, tcpsock_t *client, tcpsock_t *server){
polllist = realloc(polllist,sizeof(struct pollfd)*conn_counter+1);
int clientsd;
tcp_get_sd(server, &clientsd);
polllist[conn_counter].fd= clientsd;
polllist[conn_counter].events = POLLIN;
}
int main(void){
tcpsock_t *server;
tcpsock_t *client;
client = malloc(sizeof(get_size_tcpsock()));
struct pollfd *poll_list;
poll_list = malloc(sizeof(struct pollfd));
sensor_data_t data;
int bytes,result;
if(tcp_passive_open(&server,PORT)!=TCP_NO_ERROR)exit(EXIT_FAILURE);
int serversd;
tcp_get_sd(server, &serversd);
poll_list[0].fd = serversd;
poll_list[0].events = POLLIN;
printf("start polling \n");
while(1){
int retval,i;
retval = poll(poll_list,conn_counter+1,5000);
if (retval>0){
if(poll_list[0].revents && POLLIN>0){
tcpsock_t *requestclient;
tcp_wait_for_connection(server,&requestclient);
client[conn_counter] = *requestclient; //here i have the error
add_client(requestclient,client);
add_poll(poll_list, requestclient, server);
}
for (i=0; i<conn_counter+1;i++){
if(poll_list[i+1].revents & POLLIN){
bytes = sizeof(data.id);
result = tcp_receive(client[i],(void *)&data.id,&bytes); //here i have the error
bytes = sizeof(data.value);
result = tcp_receive(client[i],(void *)&data.value,&bytes); //here i have the error
bytes = sizeof(data.ts);
result =tcp_receive(client[i],(void *)&data.ts,&bytes); //here i have the error
if ((result==TCP_NO_ERROR) && bytes){
printf("sensor id = %" PRIu16 " - temperature = %g - timestamp = %ld\n", data.id, data.value, (long int)data.ts);
}
fflush(stdout);
}
if (poll_list[i+1].revents & POLLHUP){
printf("client disconnected \n");
poll_list[conn_counter+1].fd=-1;
poll_list[conn_counter+1].events=0;
fflush(stdout);
}
}
}
}
tcp_close(&server);
return 1;
}
Here is the tcpsock.h, but the functions work fine.
typedef struct tcpsock tcpsock_t;
int get_size_tcpsock();
int tcp_passive_open(tcpsock_t ** socket, int port);
/* Creates a new socket and opens this socket in 'passive listening mode' (waiting for an active connection setup request)
* The socket is bound to port number 'port' and to any active IP interface of the system
*/
int tcp_active_open(tcpsock_t ** socket, int remote_port, char * remote_ip);
/* Creates a new TCP socket and opens a TCP connection to the system with IP address 'remote_ip' on port 'remote_port'
* The newly created socket is return as '*socket'
*/
int tcp_close(tcpsock_t ** socket);
int tcp_wait_for_connection(tcpsock_t * socket, tcpsock_t ** new_socket);
/* Puts the socket 'socket' in a blocking wait mode
* Returns when an incoming TCP connection setup request is received
* A newly created socket identifying the remote system that initiated the connection request is returned as '*new_socket'
*/
int tcp_send(tcpsock_t * socket, void * buffer, int * buf_size );
/* Initiates a send command on the socket 'socket' and tries to send the total '*buf_size' bytes of data in 'buffer' (recall that the function might block for a while)
* The function sets '*buf_size' to the number of bytes that were really sent, which might be less than the initial '*buf_size'
*/
int tcp_get_ip_addr( tcpsock_t * socket, char ** ip_addr);
/* Set '*ip_addr' to the IP address of 'socket' (could be NULL if the IP address is not set)
*/
int tcp_get_port(tcpsock_t * socket, int * port);
int tcp_get_sd(tcpsock_t * socket, int * sd);

Related

Is there a way to call library thread-local init/cleanup on thread creation/destruction?

This question is similar to How to call a function on a thread's creation and exit? but more specific. In another multi-process shared memory project I used a combination of an __attribute__((constructor)) labeled library init routine, lazy initialisation for each thread, and robust futexes to make sure resources weren't leaked in the shared memory even if a sys admin chose to SIGKILL one of the processes using it. However futexes within the APIs are way too heavyweight for my current project and even the few instructions to deke around some lazy initialisation is something I'd rather avoid. The library APIs will literally be called several trillion times over a few hundred threads across several processes (each API is only a couple hundred instructions.)
I am guessing the answer is no, but since I spent a couple hours looking for and not finding a definitive answer I thought I'd ask it here, then the next person looking for a simple answer will be able to find it more quickly.
My goal is pretty simple: perform some per-thread initialisation as threads are created in multiple processes asynchronously, and robustly perform some cleanup at some point when threads are destroyed asynchronously. Doesn't have to be immediately, it just has to happen eventually.
Some hypothetical ideas to engage critical thinking: a hypothetical pthread_atclone() called from an __attribute__((constructor)) labeled library init func would satisfy the first condition. And an extension to futex()es to add a semop-like operation with a per-thread futex_adj value that, if non-zero in do_exit(), causes FUTEX_OWNER_DIED to be set for the futex "semaphore" allowing cleanup the next time the futex is touched.
Well, first, you should document that library users should not asynchronously terminate threads in such a manner that they dont explictly release resources belonging to your library, (closing a handle, whatever), TBH, just terminating threads at all before process termination is a bad idea.
It's more difficult to detect if a whole process is SIGKILLed while it's using your lib. My current best guess is that all processes wishing to use your library have to log in first so that their pid can be added to a container. Using a thread started at your lib initialization, poll for pid's that have diappeared with kill(pid,0) and take any approriate cleanup. It's not very satisfactory, (I hate polling), but I don't see any alternatives that are not grossly messy:(
After research and experimentation I've come up with what seems to be current "best practice" as far as I can tell. If anyone knows any better, please comment!
For the first part, per-thread initialisation, I was not able to come up with any alternative to straightforward lazy initialisation. However, I did decide that it's slightly more efficient to move the branch to the caller so that pipelining in the new stack frame isn't immediately confronted with an effectively unnecessary branch. so instead of this:
__thread int tInf = 0;
void
threadDoSomething(void *data)
{
if (!tInf) {
_threadInitInfo(&tInf);
}
/*l
* do Something.
*/
}
This:
__thread int tInf = 0;
#define threadDoSomething(data) (((!tInf)?_threadInitInfo(&tInf):0), \
_threadDoSomething((data)))
void
_threadDoSomething(void *data)
{
/*l
* do Something.
*/
}
Comments on the (admittedly slight) usefulness of this welcome!
For the second part, robustly performing some cleanup when threads die no matter how asynchronously, I was not able to find any solution better than to have a reaping process epoll_wait() on a file descriptor for the read end of an open pipe passed to it via an SCM_RIGHTS control message in a sendmsg() call on an abstract UNIX domain socket address. Sounds complex, but it's not that bad, here's the client side:
/*m
* Client that registers a thread with a server who will do cleanup of a
* shared interprocess object even if the thread dies asynchronously.
*/
#include <sys/socket.h> // socket(), bind(), recvmsg()
#include <sys/syscall.h> // syscall()
#include <sys/un.h> // sockaddr_un
#include <stdint.h> // uint64_t
#include <fcntl.h> // O_CLOEXEC()
#include <malloc.h> // malloc()
#include <stdlib.h> // random()
#include <unistd.h> // close(), usleep()
#include <pthread.h> // pthread_create()
#include <tsteplsrv.h> // Our API.
char iovBuf[] = "SP1"; // 3 char buf to send client type
__thread pid_t cliTid = 0; // per-thread copy of self's Thread ID
/*f
* initClient() is called when we realise we need to lazily initialise
* our thread based on cliTid being zero.
*/
void *
initClient(void *ptr)
{
struct sockaddr_un svAddr;
struct msghdr msg;
struct iovec io;
struct cmsghdr *ctrMsg;
uint64_t ltid; // local 8-byte copy of the tid
int pfds[2], // two fds of our pipe
sfd; // socket fd
/*s
* This union is necessary to ensure that the buffer is aligned such that
* we can read cmsg_{len,level,type} from the cmsghdr without causing an
* alignment fault (SIGBUS.)
*/
union {
struct cmsghdr hdr;
char buf[CMSG_SPACE(sizeof(int))];
} ctrBuf;
pfds[0] = pfds[1] = sfd = -1;
/*l
* Get our Thread ID.
*/
ltid = (uint64_t)(cliTid = syscall(SYS_gettid));
/*l
* Set up an abstract unix domain socket address.
*/
svAddr.sun_family = AF_UNIX;
svAddr.sun_path[0] = '\0';
strcpy(&svAddr.sun_path[1], EPLS_SRV_ADDR);
/*l
* Set up a socket datagram send buffer.
*/
io.iov_base = iovBuf;
io.iov_len = sizeof(iovBuf);
msg.msg_iov = &io;
msg.msg_iovlen = 1;
msg.msg_control = ctrBuf.buf;
msg.msg_controllen = sizeof(ctrBuf);
msg.msg_name = (struct sockaddr *)&svAddr,
msg.msg_namelen = (&svAddr.sun_path[0] - (char *)&svAddr)
+ 1
+ sizeof(EPLS_SRV_ADDR);
/*l
* Set up the control message header to indicate we are sharing a file
* descriptor.
*/
ctrMsg = CMSG_FIRSTHDR(&msg);
ctrMsg->cmsg_len = CMSG_LEN(sizeof(int));
ctrMsg->cmsg_level = SOL_SOCKET;
ctrMsg->cmsg_type = SCM_RIGHTS;
/*l
* Create file descriptors with pipe().
*/
if (-1 == pipe(pfds)) {
printErrMsg("TID: %d pipe() failed", cliTid);
} else {
/*l
* Write our tid to the pipe.
*/
memmove(CMSG_DATA(ctrMsg), &pfds[0], sizeof(int));
if (-1 == write(pfds[1], &ltid, sizeof(uint64_t))) {
printErrMsg("TID: %d write() failed", cliTid);
} if (-1 == (sfd = socket(AF_UNIX, SOCK_DGRAM, 0))) {
printErrMsg("TID: %d socket() failed", cliTid);
} else if (-1 == sendmsg(sfd, &msg, 0)) {
printErrMsg("TID: %d sendmsg() failed", cliTid);
} else {
printVerbMsg("TID: %d sent write fd %d to server kept read fd %d",
cliTid,
pfds[0],
pfds[1]);
/*l
* Close the read end of the pipe, the server has it now.
*/
close(pfds[0]);
pfds[0] = -1;
}
}
if (-1 != pfds[1]) close(pfds[1]);
if (-1 != pfds[0]) close(pfds[0]);
if (-1 != sfd) close(sfd);
return (void *)0;
}
And the reaper's code:
/*m
* Abstract datagram socket listening for FD's from clients.
*/
#include <sys/socket.h> // socket(), bind(), recvmsg()
#include <sys/epoll.h> // epoll_{create,wait}()
#include <sys/un.h> // sockaddr_un
#include <malloc.h> // malloc()
#include <unistd.h> // close()
#include <tsteplsrv.h> // Our API.
/*s
* socket datagram structs for receiving structured messages used to transfer
* fds from our clients.
*/
struct msghdr msg = { 0 };
struct iovec io = { 0 };
char iovBuf[EPLS_MSG_LEN]; // 3 char buf to receive client type
/*s
* This union is necessary to ensure that the buffer is aligned such that
* we can read cmsg_{len,level,type} from the cmsghdr without causing an
* alignment fault (SIGBUS.)
*/
union {
struct cmsghdr hdr;
char buf[CMSG_SPACE(sizeof(int))];
} ctrBuf;
typedef struct _tidFd_t {
struct _tidFd_t *next;
pid_t tid;
int fd;
} tidFd_t;
tidFd_t *tidFdLst = (tidFd_t *)0;
/*f
* Perform some handshaking with a new client and add the file descriptor
* it shared with us to the epoll set.
*/
static void
welcomeClient(int efd, int cfd)
{
uint64_t tid;
tidFd_t *tfd;
struct epoll_event epEv;
tfd = (tidFd_t *)-1;
/*l
* The fd is a pipe and should be readable, and should contain the
* tid of the client.
*/
if (-1 != read(cfd, &tid, sizeof(tid)) && (tfd = malloc(sizeof(*tfd)))) {
tfd->fd = cfd;
tfd->tid = (pid_t)tid;
tfd->next = tidFdLst;
/*l
* Single threaded process, no race condition here.
*/
tidFdLst = tfd;
/*l
* Add the fd to the epoll() set so that we will be woken up with
* an error if the thread dies.
*/
epEv.events = EPOLLIN;
epEv.data.fd = cfd;
if (-1 == epoll_ctl(efd, EPOLL_CTL_ADD, cfd, &epEv)) {
printErrMsg("TID: %ld Could not register fd %d with epoll set",
tid,
cfd);
} else {
printVerbMsg("TID: %ld Registered fd %d with epoll set", tid, cfd);
}
/*l
* Couldn't allocate memory for the new client.
*/
} else if (!tfd) {
printErrMsg("Could not allocate memory for new client");
/*l
* Could not read from the eventfd() file descriptor.
*/
} else {
printErrMsg("Could not read from client file descriptor");
}
}
/*f
* Perform some handshaking with a new client and add the file descriptor
* it shared with us to the epoll set.
*/
static void
processClientEvent(int efd, struct epoll_event *epEv)
{
tidFd_t *tfd, **bLnk;
/*l
* Walk the list of per-tid fd structs.
*/
for (bLnk = &tidFdLst; (tfd = *bLnk); bLnk = &tfd->next)
if (tfd->fd == epEv->data.fd)
break;
if (!tfd) {
printErrMsg("client file descriptor %d not found on the tfd list!",
epEv->data.fd);
/*l
* If we received an EPOLLHUP on the fd, cleanup.
*/
} else if (epEv->events & EPOLLHUP) {
/*l
* Try to remove the tid's pipe fd from the epoll set.
*/
if (-1 == epoll_ctl(efd, EPOLL_CTL_DEL, epEv->data.fd, epEv)) {
printErrMsg("couldn't delete epoll for tid %d", tfd->tid);
/*l
* Do tid cleanup here.
*/
} else {
printVerbMsg("TID: %d closing fd: %d", tfd->tid, epEv->data.fd);
close(epEv->data.fd);
/*l
* Remove the per-tid struct from the list and free it.
*/
*bLnk = tfd->next;
free(tfd);
}
} else {
printVerbMsg("TID: %d Received unexpected epoll event %d",
tfd->tid,
epEv->events);
}
}
/*f
* Create and listen on a datagram socket for eventfd() file descriptors
* from clients.
*/
int
main(int argc, char *argv[])
{
struct sockaddr_un svAddr;
struct cmsghdr *ctrMsg;
struct epoll_event *epEv,
epEvs[EPLS_MAX_EPEVS];
int sfd, efd, cfd, nfds;
sfd = efd = -1;
/*l
* Set up an abstract unix domain socket address.
*/
svAddr.sun_family = AF_UNIX;
svAddr.sun_path[0] = '\0';
strcpy(&svAddr.sun_path[1], EPLS_SRV_ADDR);
/*l
* Set up a socket datagram receive buffer.
*/
io.iov_base = iovBuf; // 3-char buffer to ID client type
io.iov_len = sizeof(iovBuf);
msg.msg_name = (char *)0; // No need for the client addr
msg.msg_namelen = 0;
msg.msg_iov = &io; // single IO vector in the S/G array
msg.msg_iovlen = 1;
msg.msg_control = ctrBuf.buf; // Control message buffer
msg.msg_controllen = sizeof(ctrBuf);
/*l
* Set up an epoll event.
*/
epEv = &epEvs[0];
epEv->events = EPOLLIN;
/*l
* Create a socket to receive datagrams on and register the socket
* with our epoll event.
*/
if (-1 == (epEv->data.fd = sfd = socket(AF_UNIX, SOCK_DGRAM, 0))) {
printErrMsg("socket creation failed");
/*l
* Bind to the abstract address. The pointer math is to portably
* handle weird structure packing _just_in_case_.
*/
} else if (-1 == bind(sfd,
(struct sockaddr *)&svAddr,
(&svAddr.sun_path[0] - (char *)&svAddr)
+ 1
+ sizeof(EPLS_SRV_ADDR))) {
printErrMsg("could not bind address: %s", &svAddr.sun_path[1]);
/*l
* Create an epoll interface. Set CLOEXEC for tidiness in case a thread
* in the server fork()s and exec()s.
*/
} else if (-1 == (efd = epoll_create1(EPOLL_CLOEXEC))) {
printErrMsg("could not create epoll instance");
/*l
* Add our socket fd to the epoll instance.
*/
} else if (-1 == epoll_ctl(efd, EPOLL_CTL_ADD, sfd, epEv)) {
printErrMsg("could not add socket to epoll instance");
/*l
* Loop receiving events on our epoll instance.
*/
} else {
printVerbMsg("server listening on abstract address: %s",
&svAddr.sun_path[1]);
/*l
* Loop forever listening for events on the fds we are interested
* in.
*/
while (-1 != (nfds = epoll_wait(efd, epEvs, EPLS_MAX_EPEVS, -1))) {
/*l
* For each fd with an event, figure out what's up!
*/
do {
/*l
* Transform nfds from a count to an index.
*/
--nfds;
/*l
* If the fd with an event is the listening socket a client
* is trying to send us their eventfd() file descriptor.
*/
if (sfd == epEvs[nfds].data.fd) {
if (EPOLLIN != epEvs[nfds].events) {
printErrMsg("unexpected condition on socket: %d",
epEvs[nfds].events);
nfds = -1;
break;
}
/*l
* Reset the sizes of the receive buffers to their
* actual value; on return they will be set to the
* read value.
*/
io.iov_len = sizeof(iovBuf);
msg.msg_controllen = sizeof(ctrBuf);
/*l
* Receive the waiting message.
*/
if (-1 == recvmsg(sfd, &msg, MSG_CMSG_CLOEXEC)) {
printVerbMsg("failed datagram read on socket");
/*l
* Verify that the message's control buffer contains
* a file descriptor.
*/
} else if ( NULL != (ctrMsg = CMSG_FIRSTHDR(&msg))
&& CMSG_LEN(sizeof(int)) == ctrMsg->cmsg_len
&& SOL_SOCKET == ctrMsg->cmsg_level
&& SCM_RIGHTS == ctrMsg->cmsg_type) {
/*l
* Unpack the file descriptor.
*/
memmove(&cfd, CMSG_DATA(ctrMsg), sizeof(cfd));
printVerbMsg("Received fd %d from client type %c%c%c",
cfd,
((char *)msg.msg_iov->iov_base)[0],
((char *)msg.msg_iov->iov_base)[1],
((char *)msg.msg_iov->iov_base)[2]);
/*l
* Process the incoming file descriptor and add
* it to the epoll() list.
*/
welcomeClient(efd, cfd);
/*l
* Note but ignore incorrectly formed datagrams.
*/
} else {
printVerbMsg("could not extract file descriptor "
"from client's datagram");
}
/*l
* The epoll() event is on one of the file descriptors
* shared with a client, process it.
*/
} else {
processClientEvent(efd, &epEvs[nfds]);
}
} while (nfds);
/*l
* If something happened to our socket break the epoll_wait()
* loop.
*/
if (nfds)
break;
}
}
/*l
* An error occurred, cleanup.
*/
if (-1 != efd)
close(efd);
if (-1 != sfd)
close(sfd);
return -1;
}
At first I tried using eventfd() rather than pipe() but eventfd file descriptors represent objects not connections, so closing the fd in the client code did not produce an EPOLLHUP in the reaper. If anyone knows of a better alternative to pipe() for this, let me know!
For completeness here's the #defines used to construct the abstract address:
/*d
* server abstract address.
*/
#define EPLS_SRV_NAM "_abssSrv"
#define EPLS_SRV_VER "0.0.1"
#define EPLS_SRV_ADDR EPLS_SRV_NAM "." EPLS_SRV_NAM
#define EPLS_MSG_LEN 3
#define EPLS_MAX_EPEVS 32
That's it, hope this is useful for someone.

Issues with socket and server in C (Name or service not known error)

I am working on a client/server program that is supposed to take user input (two integers) and allow the user to calculate those to receive an answer.
When I run my program there seems to be an issue with either connecting to the client or opening the directory and I'm not sure what it could be. I'm entirely new to setting up servers and utilizing directories to read and write .txt files to.
Here are the parts of code that I think might be wrong and causing the issues I am facing, which is the program asks for a port number to connect to (2000 is what is recommended to use) so I enter that and then nothing happens.
// PURPOSE: To run the server by 'accept()'-ing client requests from
// 'listenFd' and doing them.
void doServer (int listenFd)
{
/* Application validity check: */
/* Server clients: */
pthread_t threadId;
pthread_attr_t threadAttr;
int threadCount = 0;
int *iPtr;
/* YOUR CODE HERE: */
while(1)
{
/* Accept connection to client: */
int connfd = accept(listenFd, NULL, NULL); //if I change this to getServerFileDescriptor (another function within the code, it will continuously loop through threadNumbers and do nothing as well).
/* Malloc memory for two integers: */
iPtr = (int *)calloc(2, sizeof(int));
/*Put file descriptor in the first space: */
iPtr[0] = listenFd; // or just listenFd not sure
/* put threadCount into the second space and increment: */
iPtr[1] = threadCount++;
/* Creates detached thread for handleClient and passes the address of iPtr */
pthread_attr_init(&threadAttr);
pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_DETACHED);
pthread_create(&threadId, &threadAttr, handleClient, (void*)iPtr);
pthread_join(threadId, NULL);
pthread_attr_destroy(&threadAttr);
}
}
void* handleClient(void* vPtr)
{
/* Read command: */
char buffer[BUFFER_LEN];
char command;
int fileNum;
char text[BUFFER_LEN];
int shouldContinue = 1;
int threadNum;
int fd;
/* Cast void* vPtr back to an int */
int *iPtr = (int *)vPtr;
/* Assign file descriptor to a local value named 'fd'*/
fd = iPtr[0];
/* Assign thread number to local value named 'threadNum'*/
threadNum = iPtr[1];
free(iPtr);
while (shouldContinue)
{
memset(buffer,'\0',BUFFER_LEN);
memset(text ,'\0',BUFFER_LEN);
read(fd,buffer,BUFFER_LEN);
printf("Thread %d received: %s\n",threadNum,buffer);
sscanf(buffer,"%c %d \"%[^\"]\"",&command,&fileNum,text);
/* YOUR CODE HERE: */
if(command == DIR_CMD_CHAR)
{
/* 1. Open the current directory (named "."). If an error occurs then just send STD_ERROR_MSG back to the client: */
DIR* dirPtr = opendir(".");
struct dirent* entryPtr;
/* If error occurs send STD_ERROR_MSG to client: */
if ((dirPtr = opendir (".")) == NULL) {
{
write(fd, STD_ERROR_MSG, sizeof(STD_ERROR_MSG));
//return(EXIT_FAILURE);
}
/* Read as many entries that will fit into BUFFER_LEN
put as many entries into the buffer and send the buffer to client
d_name=entryPtr into the bufffer using strcat_s,
make sure buffer starts empty
buffer[0]='\n';
add new line char using stringcat "\n"
make sure do not go over buffer lengh */
if (dirPtr)
{
while ((entryPtr = readdir(dirPtr)) != NULL)
{
buffer[0]='\0';
int i;
int sizebuf = sizeof(buffer);
for (i = 0; i < sizebuf; i++)
{
strcat(buffer,entryPtr->d_name);
strcat(buffer,"\n");
}
}
}
/* 3. Close directory */
closedir(dirPtr);
}
Here's how the correct output should look.
$ ./mathClient Machine name [localhost.localdomain]? (I just pressed enter)
Port number? 2000
What would you like to do:
(1) List files
(2) Read a math file
(3) Write a math file
(4) Calculate a math file
(5) Delete a math file
(0) Quit
Your choice? 1
Sending "l"
0.bc
Here are the instructions for the code that I am having trouble with.
Implementing doServer(int listenFd) (10 Points):
doServer() should have a loop in which it waits for a client to connect to listenFd. When a client does, it should:
malloc() enough memory for 2 integers
put the file descriptor from accept() in one of those spaces
put the value of threadCount in the other space, and increment threadCount
Make a detached thread to handle this new client. I called my function handleClient(), but you may call yours whatever. Pass the address of your malloc()-ed array.
The loop should then go back for another accept().
void* handleClient(void* vPtr) (10 Points):
(Or whatever you call your function that runs a thread for the client.)
The thread id and the file descriptor are passed, but they come in as a void* pointer.
Use another pointer to cast back to int*
Save the file descriptor and thread number in local vars
free() the memory
Print the thread number and do a loop like this:
// II.B. Read command:
char buffer[BUFFER_LEN];
char command;
int fileNum;
char text[BUFFER_LEN];
int shouldContinue = 1;
while (shouldContinue)
{
text[0] = '\0';
read(fd,buffer,BUFFER_LEN);
printf("Thread %d received: %s\n",threadNum,buffer);
sscanf(buffer,"%c %d \"%[^\"]\"",&command,&fileNum,text);
// YOUR CODE HERE
}
It read()s a line of text from the client into buffer[], and parses the line into a command character, fileNum integer, and quote-delineated text[] string. (The fileNum and text[] may or may not be given, depending upon the value of command.)
Then do the following operations based upon the value of command. Except for QUIT_CMD_CHAR I strongly recommend using a different function for each!
When the function ends just have it do:
printf("Thread %d quitting.\n",threadNum);
return(NULL);
command == DIR_CMD_CHAR (15 Points):
Open the current directory (named "."). If an error occurs then just send STD_ERROR_MSG back to the client.
Copy as many entries that will fit into a buffer of length BUFFER_LEN. Be sure to put a separating '\n' after each entry.
Close the directory.
Any help would be appreciated, if you need the full code I could send that to you if that would help.
EDIT: Here are two additional functions, one called getPortNum() and another called getServerFileDescriptor() which address receiving a port number and setting up sockets for the connection. Additionally I included the main() which utilizes these.
// PURPOSE: To decide a port number, either from the command line arguments
// 'argc' and 'argv[]', or by asking the user. Returns port number.
int getPortNum (int argc,
char* argv[]
)
{
// I. Application validity check:
// II. Get listening socket:
int portNum;
if (argc >= 2)
portNum = strtol(argv[1],NULL,0);
else
{
char buffer[BUFFER_LEN];
printf("Port number to monopolize? ");
fgets(buffer,BUFFER_LEN,stdin);
portNum = strtol(buffer,NULL,0);
}
// III. Finished:
return(portNum);
}
// PURPOSE: To attempt to create and return a file-descriptor for listening
// to the OS telling this server when a client process has connect()-ed
// to 'port'. Returns that file-descriptor, or 'ERROR_FD' on failure.
int getServerFileDescriptor
(int port
)
{
// I. Application validity check:
// II. Attempt to get socket file descriptor and bind it to 'port':
// II.A. Create a socket
int socketDescriptor = socket(AF_INET, // AF_INET domain
SOCK_STREAM, // Reliable TCP
0);
if (socketDescriptor < 0)
{
perror(THIS_PROGRAM_NAME);
return(ERROR_FD);
}
// II.B. Attempt to bind 'socketDescriptor' to 'port':
// II.B.1. We'll fill in this datastruct
struct sockaddr_in socketInfo;
// II.B.2. Fill socketInfo with 0's
memset(&socketInfo,'\0',sizeof(socketInfo));
// II.B.3. Use TCP/IP:
socketInfo.sin_family = AF_INET;
// II.B.4. Tell port in network endian with htons()
socketInfo.sin_port = htons(port);
// II.B.5. Allow machine to connect to this service
socketInfo.sin_addr.s_addr = INADDR_ANY;
// II.B.6. Try to bind socket with port and other specifications
int status = bind(socketDescriptor, // from socket()
(struct sockaddr*)&socketInfo,
sizeof(socketInfo)
);
if (status < 0)
{
perror(THIS_PROGRAM_NAME);
return(ERROR_FD);
}
// II.B.6. Set OS queue length:
listen(socketDescriptor,5);
// III. Finished:
return(socketDescriptor);
}
int main (int argc,
char* argv[]
)
{
// I. Application validity check:
// II. Do server:
int port = getPortNum(argc,argv);
int listenFd = getServerFileDescriptor(port);
int status = EXIT_FAILURE;
if (listenFd >= 0)
{
doServer(listenFd);
close(listenFd);
status = EXIT_SUCCESS;
}
// III. Finished:
return(status);

Polling TCP connections in C

I'm working on a school task where i have to make a server that gets TCP connections. Those connections then pass data. I use poll() to see if there is a new connection request or if there is incoming data from an existing connection. It's used with the loop back address (127.0.0.1).
It works fine when i have 1 connection, but when i open a second one, it stops polling and wait for the data from the new connection.
The strange thing is, that if i open a third connection, it does give the data of that third connection as well, but still no polling, just waiting.
I read a lot about it and i'm stuck on it for a while.
I wrote the server-code in the connmgr.c (with a lot of printf's for finding my mistake). I'll explain below:
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <assert.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <syslog.h>
#include <poll.h>
#include "connmgr.h"
#define _GNU_SOURCE
static FILE * write_file;
struct pollfd *poll_list;
int serversd;
int conn_counter = 0;
int dplist_errno;
dplist_t * list = NULL;
list_node_t * dummy = NULL;
void * element_copy(void *element);
void element_free(void **element);
int element_compare(void *x, void *y);
void add_poll(struct pollfd * polllist, tcpsock_t *client, tcpsock_t *server){
conn_counter++;
polllist = realloc(polllist,sizeof(struct pollfd)*conn_counter+1);
int clientsd;
tcp_get_sd(client, &clientsd);
polllist[conn_counter].fd= clientsd;
//printf("fd in add_poll = %d \n",clientsd);
polllist[conn_counter].events = POLLIN;
}
int stop = 0;
tcpsock_t *server, *client;
void connmgr_listen(int port_number){
sensor_data_t data;
dummy = malloc(sizeof(list_node_t));
write_file = fopen("sensor_data_recv", "w");
poll_list = malloc(sizeof(struct pollfd));
list = dpl_create(&element_copy, &element_free, &element_compare);
if(tcp_passive_open(&server,port_number)!=TCP_NO_ERROR)exit(EXIT_FAILURE);
tcp_get_sd(server, &serversd);
poll_list[0].fd = serversd;
poll_list[0].events = POLLIN;
printf("server fd = %d \n",serversd);
printf("start with fd %d = %d \n", 0,poll_list[0].fd);
int bytes,result;
int test = 0;
while(1){
test++;
int sd;
int return_value,i;
return_value = poll(poll_list,conn_counter+1,TIMEOUT);
if (return_value>0){
if(poll_list[0].revents & POLLIN>0){
printf("add client\n");
tcpsock_t * requestclient;
if (tcp_wait_for_connection(server,&requestclient)!=TCP_NO_ERROR) exit(EXIT_FAILURE);
tcp_get_sd(requestclient, &sd);
dummy->sd = sd;
printf("inserted sd = %d \n",sd);
dummy->client = requestclient;
time(&(dummy->ts));
list = dpl_insert_at_index(list, dummy, conn_counter,true);
//printf("sd from client = %d \n", tcp_get_sd(client, &sd));
add_poll(poll_list, dummy->client, server);
printf("conn_counter = %d \n",conn_counter);
}
//for (i=0; i<conn_counter;i++){
i=0;
while(i<conn_counter){
if(poll_list[i+1].revents & POLLIN>0){
printf("poll in %d \n",i+1);
dummy = (list_node_t *) dpl_get_element_at_index(list,i);
time(&(dummy->ts));
client = dummy->client;
sd = dummy->sd;
/*for(int l = 0; l<conn_counter;l++){
printf("sensor %d \n",l);
}*/
bytes = sizeof(data.id);
printf("# line %d en i = %d \n", __LINE__,i);result = tcp_receive(client,(void *)&data.id,&bytes);
bytes = sizeof(data.value);
printf("# line %d \n", __LINE__);result = tcp_receive(client,(void *)&data.value,&bytes);
bytes = sizeof(data.ts);
printf("# line %d \n", __LINE__);result = tcp_receive(client,(void *)&data.ts,&bytes);
if ((result==TCP_NO_ERROR) && bytes){
printf("sensor id = %" PRIu16 " - temperature = %g - timestamp = %ld\n", data.id, data.value, (long int)data.ts);
}
else{
if(result == TCP_CONNECTION_CLOSED){printf("peer left \n");}
else{"error in peerconnection \n";}
tcp_close(&client);
list = dpl_remove_at_index(list, i, true);
}
fflush(stdout);
}
if (poll_list[i+1].revents & POLLHUP){
printf("client disconnected \n");
poll_list[conn_counter+1].fd=-1;
poll_list[conn_counter+1].events=0;
fflush(stdout);
}i++;
}
}
//if(return_value<0){exit(EXIT_FAILURE);}
//if(stop == 1){break;}
printf("end of while %d \n",test);
}
Once a server has started in the tcp_passive_open, it will start polling untill the return_value is high. Then it checks if the POLLIN is at [0], what means a new connection request. If not, i check all the connections in the poll_list, starting from 1 untill conn_counter. If not, i check for a POLLHUP and set the fd of that client at -1 so poll() will ignore this.
I think it should be somewhere where i use the while-loop to check if the POLLIN is from one of the connections, because i can add connections no problem.
the dpl_... functions are from a dubble-linked-list library i wrote myself and should work fine. They create a list, get an element at an index... The list uses 3 callback functions.
The tcp_... functions are functions i've got from the prof. The tcpsock.h file should give enough information:
typedef struct tcpsock tcpsock_t;
int get_size_tcpsock();
// All functions below return TCP_NO_ERROR if no error occurs during execution
int tcp_passive_open(tcpsock_t ** socket, int port);
/* Creates a new socket and opens this socket in 'passive listening mode' (waiting for an active connection setup request)
* The socket is bound to port number 'port' and to any active IP interface of the system
* The number of pending connection setup requests is set to MAX_PENDING
* The newly created socket is returned as '*socket'
* This function is typically called by a server
*/
int tcp_active_open(tcpsock_t ** socket, int remote_port, char * remote_ip);
/* Creates a new TCP socket and opens a TCP connection to the system with IP address 'remote_ip' on port 'remote_port'
* The newly created socket is return as '*socket'
* This function is typically called by a client
int tcp_close(tcpsock_t ** socket);
/* The socket '*socket' is closed , allocated resources are freed and '*socket' is set to NULL
* If '*socket' is connected, a TCP shutdown on the connection is executed
*/
int tcp_wait_for_connection(tcpsock_t * socket, tcpsock_t ** new_socket);
/* Puts the socket 'socket' in a blocking wait mode
* Returns when an incoming TCP connection setup request is received
* A newly created socket identifying the remote system that initiated the connection request is returned as '*new_socket'
*/
int tcp_send(tcpsock_t * socket, void * buffer, int * buf_size );
/* Initiates a send command on the socket 'socket' and tries to send the total '*buf_size' bytes of data in 'buffer' (recall that the function might block for a while)
* The function sets '*buf_size' to the number of bytes that were really sent, which might be less than the initial '*buf_size'
*/
int tcp_receive (tcpsock_t * socket, void * buffer, int * buf_size);
/* Initiates a receive command on the socket 'socket' and tries to receive the total '*buf_size' bytes of data in 'buffer' (recall that the function might block for a while)
* The function sets '*buf_size' to the number of bytes that were really received, which might be less than the inital '*buf_size'
*/
int tcp_get_ip_addr( tcpsock_t * socket, char ** ip_addr);
/* Set '*ip_addr' to the IP address of 'socket' (could be NULL if the IP address is not set)
* No memory allocation is done (pointer reference assignment!), hence, no free must be called to avoid a memory leak
*/
int tcp_get_port(tcpsock_t * socket, int * port);
/* Return the port number of the 'socket'
*/
int tcp_get_sd(tcpsock_t * socket, int * sd);
/* Return the socket descriptor of the 'socket'
*/
Thank you for reading this and i hope you can help me!
ps, i have still some problems when i disconnect a tcp and then connect with another one, but that are problems for later :)
In your function
void add_poll(struct pollfd * polllist, tcpsock_t *client, tcpsock_t *server)
You're reallocating the pollfd buffer containing the sockets fd's, but you're getting the result in a temporary pointer variable (polllist) instead of your global variable "poll_list". Realloc may or may not move the memory to another location if it can just extend it.
When you get back into your loop, nothing has changed, you're still using the same buffer -that may have been freed !- containing the server socket and the first connection, and somewhere else in memory, there is a buffer with your 3 sockets.
So either pass a pointer on pointer (struct pollfd **polllist), or set the "poll_list" variable instead :).
Also, if I'm not mistaken, in your loop, when you do :
if(poll_list[i+1].revents & POLLIN>0)
The ">" operator has a higher priority than the "&" operator, so it's equivalent to :
if(poll_list[i+1].revents & (POLLIN>0))
Just remove the "> 0", or put parenthesis around your expression

Can I implement client - client communication through server in between?

I want to send message from client A to client B, through this server. I am not sure how can I get that? One approach I can think of is making a message queue for each client and add message to that queue if someone sends message to that client, and sends from that queue to the respective client ? But I am not sure How can I implement this ? Can anyone help me with this ?
There can be n clients at any moments. In that case broadcast to all clients.
Below is my server code. I have checked username and password of the user. insidePortal() function will take care of sending message to other client.
#include<stdio.h>
#include <stdlib.h>
#include<string.h> //strlen
#include<sys/socket.h>
#include<arpa/inet.h> //inet_addr
#include<unistd.h> //write
int main(int argc , char *argv[])
{
int socket_desc , client_sock , c , read_size, pid;
struct sockaddr_in server , client;
char client_message[2000], message_sent[2000], message_recieve[2000];
//Create socket
socket_desc = socket(AF_INET , SOCK_STREAM , 0);
if (socket_desc == -1)
{
printf("Could not create socket");
}
puts("Socket created");
//Prepare the sockaddr_in structure
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons( 5550 );
//Bind
if( bind(socket_desc,(struct sockaddr *)&server , sizeof(server)) < 0)
{
//print the error message
perror("bind failed. Error");
return 1;
}
puts("bind done");
//Listen
listen(socket_desc , 3);
while (1) {
//Accept and incoming connection
puts("Waiting for incoming connections...");
c = sizeof(struct sockaddr_in);
// accept connection from an incoming client
client_sock = accept(socket_desc, (struct sockaddr *)&client, (socklen_t*)&c);
if (client_sock < 0)
{
perror("accept failed");
return 1;
}
/* Create child process */
pid = fork();
if (pid == 0) {
/* This is the client process */
close(socket_desc);
puts("Connection accepted");
char username[50], password[50];
memset(message_recieve, 0, sizeof message_recieve);
recv(client_sock , username , 2000 , 0);
printf("username of the user: %s", username);
memset(message_recieve, 0, sizeof message_recieve);
recv(client_sock , password , 2000 , 0);
printf("password of the user: %s", password);
FILE *f = fopen("registeredUsers.txt", "r");
if (f == NULL)
{
printf("Error opening file!\n");
exit(1);
}
char uname[50], pass[50];
int login = 0;
while(fscanf(f, "%s %s\n", uname, pass) > 0) {
printf("Helllo %s %s", uname, pass);
if (strcmp(username, uname)==0 && strcmp(password, pass) == 0) {
login = 1;
break;
}
}
memset(message_sent, 0, sizeof message_sent);
if (login == 1) {
strcpy(message_sent,"\n Successfull Login\n");
write(client_sock , message_sent , strlen(message_sent)); // Sends login status
insidePortal(client_sock, username);
} else {
strcpy(message_sent,"\nOops, wrong username or password. Please try again.\n");
write(client_sock , message_sent , strlen(message_sent)); // Sends login status
}
fclose(f);
if(read_size == 0)
{
puts("Client disconnected");
fflush(stdout);
}
else if(read_size == -1)
{
perror("recv failed");
}
exit(0);
} else {
close(client_sock);
}
}
return 0;
}
void insidePortal(int client_sock, char username[50]) {
}
I have this really long code I've wrote in the past that implements something similar to yours, but It's CPP, If you want too I'll post it here, but basically using message queues or multi-process programming seems kinda useless to me, If I were you I'd program it in the following way
Client code -> Two Threads
Server code -> Two Threads
Client Has two threads, and Three functions, Connect / Send / Receive
Connect - This function handles connection to server, whether you are using TCP it handles the listen-accept or if you use some UDP based made up protocol, it just handles it - makes sure you have some connectin
Send - This function sends some data to server
Receive This functino receives data from server
The flow of Client would be the following:
Client connects to server on Main thread
After connecting to server Client creates Second thread
On Main thread - Client enters some loop that reads data from user as Input then calls Send function and sends it to server
On Second thread - Client enters some loop that calls Receive
to receive data from server and prints it when data is received
that handles Client, now about Server
Server- Has Three functions and Some one Global data structure called Linked - List ( a Linked list obviously ) that would be shared by all it's threads, WaitForConnection Receive SendToAll
WaitForConnection- Simply calls the "Accept" function of sockets API ( if you're using TCP ) or if you're using some other made up protocol, this function just blocks it's thread as trying to wait for incoming connection, when some connection arrives, this function registers the connection into the global linked-list of all connections called Connection-List, with the appropriate socket and client data
SendToAll - Simply iterates all Connection-List and for every Connection within that list, It sends some data passed
Receive just receives some data but sets some timeout first, this is very important in order for Receive not to block for too long!
The flow of Server would be the following:
Main thread creats Second thread
Main thread enters some loop and calls WaitForConnection within it in order to continuously get connections and add them into Connection-List
Second thread enters some loop that iterates over Connection-List, for each connection within Connection-List, receive is called upon the appropriate socket, if some data is receive, SendToAll is called with the data received, if timeout, nothing happens, after that loop is continued and the next loop iteration is executed
SendToAll sends the data to ALL clients within Connection-List
This is some very simple Multi-Client Broadcast with Server architecture It should be really easy to implement! I hope this helps you
I Apologize in advance as this is a code I wrote a while ago so It has a lot of nesting within it, and a lot of comments!
------------------------- CLIENT CODE ----------------
// Main.cpp
#include <thread>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#pragma comment (lib, "Ws2_32.lib")
#define NAME_LENGTH 40
#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "8888"
void Receive(SOCKET* pscktConnection);
void Send(SOCKET* pscktConnection);
void main()
{
// Variable definition
int nResult;
int nNameLength = 0;
char pcNameBuffer[NAME_LENGTH];
SOCKET sckConnection = NULL;
WSADATA wsaData;
addrinfo addrAddressFormat;
addrinfo* paddrServerAddress;
// Code section
// Initialize Winsock
nResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
// If winsock dll loading has failed
if (nResult != 0)
{
std::cout << "Failed loading winsock DLL" << std::endl;
}
// DLL loaded successfully
else
{
//Setup connection info
ZeroMemory(&addrAddressFormat, sizeof(addrAddressFormat));
addrAddressFormat.ai_family = AF_INET;
addrAddressFormat.ai_socktype = SOCK_STREAM;
addrAddressFormat.ai_protocol = IPPROTO_TCP;
// Resolve the server address and port with the address setting into our final address
nResult = getaddrinfo("10.0.0.5", DEFAULT_PORT, &addrAddressFormat, &paddrServerAddress);
// Address resolving has failed
if (nResult != 0)
{
std::cout << "Some error has occured during connection establishment" << std::endl;
}
else
{
// Request user for his name
pcNameBuffer[0] = '\0';
std::cout << "PLEASE ENTER YOUR NAME -> ";
std::cin.getline(pcNameBuffer, NAME_LENGTH);
std::cout << std::endl << std::endl ;
// Creating the socket
sckConnection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// Connecting
nResult = connect(sckConnection, paddrServerAddress->ai_addr, (int)paddrServerAddress->ai_addrlen);
// Creating of the socket has failed
if (nResult == SOCKET_ERROR)
{
std::cout << "Creating of the socket has failed" << std::endl;
}
// Send server user's name
else
{
// Measure the name length
while (pcNameBuffer[nNameLength] != '\0')
{
++nNameLength;
}
// If invalid name
if (nNameLength == 0)
{
pcNameBuffer[0] = 'G';
pcNameBuffer[1] = 'U';
pcNameBuffer[2] = 'E';
pcNameBuffer[3] = 'S';
pcNameBuffer[4] = 'T';
pcNameBuffer[5] = '\0';
nNameLength = 6;
}
nResult = send(sckConnection, pcNameBuffer, nNameLength + 1, 0);
// An error has occured while sending server the user's name
if (nResult <= 0)
{
std::cout << "Some error has occured" << std::endl;
}
// Good to go
else
{
std::thread Read(Receive, &sckConnection);
Send(&sckConnection);
}
}
}
}
// cleanup resources
WSACleanup();
}
/*
* [Description]: This method is used only to read messages from server and print them
* [Paramaters]:
* pscktServerSocket - The address of the our connection socket
* [Return Value]: none
*/
void Receive(SOCKET* pscktConnection)
{
// Variable definition
int nReceivedBytes;
int nBufferLen = DEFAULT_BUFLEN;
char pcBuffer[DEFAULT_BUFLEN];
// Code section
// Keep this operation running constantly
while (true)
{
// Read from server -- NO TIME OUT NEEDED
nReceivedBytes = recv((*pscktConnection), pcBuffer, nBufferLen, 0);
// More than zero bytes received
if (nReceivedBytes > 0)
{
// Set a zero termination to simulate a string
pcBuffer[nReceivedBytes] = '\0';
std::cout << pcBuffer << std::endl;
}
// Server has closed the connection probably
else
{
// TODO - CLOSE CONNECTION
}
}
}
/*
* [Description]: This method is used only to send messages to the server
* [Paramaters]:
* pscktServerSocket - The address of the our connection socket
* [Return Value]: none
*/
void Send(SOCKET* pscktConnection)
{
// Variable definition
int nSentBytes;
int nBufferLen = DEFAULT_BUFLEN;
char pcBuffer[DEFAULT_BUFLEN];
// Code section
pcBuffer[0] = '\0';
// Keep this operation running constantly
while (true)
{
int nSentBytes = 0;
// Read
std::cin.getline(pcBuffer, nBufferLen);
// Go through string untill backslash 0
while (pcBuffer[nSentBytes] != '\0')
{
// Increase the number of bytes we want to send
++nSentBytes;
}
pcBuffer[nSentBytes] = '\0';
nSentBytes = send((*pscktConnection), pcBuffer, nSentBytes, 0);
// An error has occured
if (nSentBytes == SOCKET_ERROR)
{
// TODO - HANDLE ERROR;
}
}
}
`
------------------------- SERVER CODE ----------------
// Source.cpp
#include <thread>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#include "Client.h"
#include "Connections.h"
#pragma comment (lib, "Ws2_32.lib")
#define NAME_LENGTH 40
#define DEFAULT_BUFLEN 512
#define DEFAULT_PORT "8888"
#define MAX_CONNECTIONS 5
// Globals
Connections* conAllConnections = Connections::getInstance();
bool LoadServerSocket(SOCKET* pscktServerSocket);
void Dispatcher(SOCKET* pscktServerSocket);
void SendAll(ClientNode* pclndSenderAddress, char* pcMessageBuffer, int nLength);
void HandleConnections();
void main()
{
// Variable definition
int nResult;
SOCKET sckServerSocket = NULL;
WSADATA wsaData;
// Code section
// Initialize Winsock
nResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
// If winsock dll loading has failed
if (nResult != 0)
{
std::cout << "Failed loading winsock DLL" << std::endl;
}
// DLL loaded successfully
else
{
// If failed loading the server socket
if (!LoadServerSocket(&sckServerSocket))
{
std::cout << "Failed loading the server socket!" << std::endl;
}
else
{
std::thread dispatch(Dispatcher,&sckServerSocket);
//dispatch.join();
HandleConnections();
}
}
// cleanup resources
WSACleanup();
}
/*
* [Description]: This method is used to load and bind server socket into some pointer.
* [Paramaters]:
* pscktServerSocket - a pointer variable that we would like to load our socket into the address this pointer
* is pointing at
* [Return Value]: A boolean indication of whether our socket was created successfully
*/
bool LoadServerSocket(SOCKET* pscktServerSocket)
{
// Variable definition
int nResult;
bool bWasServerSocketCreated = false;
bool bWasAddressResolved = false;
addrinfo addrAddressFormat;
addrinfo* paddrFinalAddress = NULL;
// Code section
// Fil addrAddressFormat with zeros, and set correct settings of our desired socket
ZeroMemory(&addrAddressFormat, sizeof(addrAddressFormat));
addrAddressFormat.ai_family = AF_INET;
addrAddressFormat.ai_socktype = SOCK_STREAM;
addrAddressFormat.ai_protocol = IPPROTO_TCP;
//addrAddressFormat.ai_flags = AI_PASSIVE;
// Resolve the server address and port with the address setting into our final address
nResult = getaddrinfo("10.0.0.5", DEFAULT_PORT, &addrAddressFormat, &paddrFinalAddress);
// If resolving of the address was successful
if (nResult == 0)
{
// Set address resolving bool indication to true
bWasAddressResolved = true;
// Create server socket
(*pscktServerSocket) = socket(paddrFinalAddress->ai_family,
paddrFinalAddress->ai_socktype,
paddrFinalAddress->ai_protocol);
// Socket creating was successful
if ((*pscktServerSocket) != INVALID_SOCKET)
{
// Set socket creation indication to true
bWasServerSocketCreated = true;
// Bind our socket into our address
nResult = bind((*pscktServerSocket),
paddrFinalAddress->ai_addr,
(int)paddrFinalAddress->ai_addrlen);
// In case binding failed
if (nResult == SOCKET_ERROR)
{
closesocket((*pscktServerSocket));
bWasServerSocketCreated = false;
}
}
}
// Freeing resources
if (bWasAddressResolved)
{
freeaddrinfo(paddrFinalAddress);
}
return (bWasServerSocketCreated);
}
/*
* [Description]: This uses the loaded server socket and handles incoming requests for connections
* [Paramaters]:
* pscktServerSocket - a pointer to the loaded server socket
* [Return Value]: none
*/
void Dispatcher(SOCKET* pscktServerSocket)
{
// Variable definition
int nResult;
char pcBuffer[NAME_LENGTH];
DWORD timeout = 1500;
SOCKET sckClientSocket;
Client clntNewClient;
// Code section
// Keep this running constantly
while (true)
{
// Keep this running as long as we have the sufficient amount of connections
while (conAllConnections->getNumOfConnections() < MAX_CONNECTIONS)
{
// Attempt listening on the server socket
nResult = listen((*pscktServerSocket), MAX_CONNECTIONS);
// Listening was a failure
if (nResult == SOCKET_ERROR)
{
std::cout << "Failed listening with the server socket" << std::endl;
// HANDLE ERROR - TODO
}
// Listening was successful
else
{
std::cout << "Listening...." << std::endl;
// Accept a client socket
sckClientSocket = accept((*pscktServerSocket), NULL, NULL);
// Accepting was a failure
if (sckClientSocket == INVALID_SOCKET)
{
std::cout << "Client accepting has failed" << std::endl;
// HANDLE ERROR - TODO
}
// Client was added successfully
else
{
setsockopt(sckClientSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
nResult = recv(sckClientSocket, pcBuffer, NAME_LENGTH, 0);
// If received a valid username
if (nResult > 0)
{
timeout = 1;
std::cout << "New Client -> " << pcBuffer << std::endl;
clntNewClient.setClientSocket(sckClientSocket);
clntNewClient.setIsAdmin(false);
clntNewClient.setClientName(pcBuffer);
setsockopt(clntNewClient.getClientSocket(), SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));
conAllConnections->Add(clntNewClient);
// Receive until the peer shuts down the connection
}
}
}
}
}
}
/*
* [Description]: This method forwards a message to all other clients but the client who sent it
* [Paramaters]:
* pclndSenderAddress - The address of the client node who sent the
* pcMessageBuffer- a pointer to the message buffer
* nLength - the length of the message
* [Return Value]: none
*/
void SendAll(ClientNode* pclndSenderAddress, char* pcMessageBuffer, int nLength)
{
// Variable definition
int nError;
int nResult;
Client clntCurrentClient;
ClientNode* pclndCurrentNode;
ClientNode* pclndNextNode;
// Code section
// Set first node
pclndCurrentNode = conAllConnections->getFirst();
// Go through all connections
while (pclndCurrentNode != NULL)
{
// Save the next node in this phase of the code in order to avoid corruption of memory
// in case node would be deleted from dynamic allocated memory and we wont be able to call the next val upon it
pclndNextNode = pclndCurrentNode->getNext();
// Compare addresses, we do not want to forward the message to the sender
if (pclndCurrentNode != pclndSenderAddress)
{
clntCurrentClient = pclndCurrentNode->getClient();
// Forward the message
nResult = send(clntCurrentClient.getClientSocket(), pcMessageBuffer, nLength, 0);
// An error has occured
if (nResult == SOCKET_ERROR)
{
nError = WSAGetLastError();
// TODO -- handle later
}
}
// Forward current node
pclndCurrentNode = pclndNextNode;
}
}
/*
* [Description]: This method handles and receives messages from our clients and forwards them
* [Paramaters]: none
* [Return Value]: none
*/
void HandleConnections()
{
// Variable definition
int nIndex;
int nError;
int nRecvLen;
int nNameLen;
int nRecvbuflen = DEFAULT_BUFLEN;
char pcBuffer[DEFAULT_BUFLEN + NAME_LENGTH + 3];
Client clntCurrentClient;
ClientNode* pclndCurrentNode;
ClientNode* pclndNextNode;
// Code section
// Keep this going constantly
while (true)
{
pclndCurrentNode = conAllConnections->getFirst();
// Go through all connections
while (pclndCurrentNode != NULL)
{
clntCurrentClient = pclndCurrentNode->getClient();
// Save the next node in this phase of the code in order to avoid corruption of memory
// in case node would be deleted from dynamic allocated memory and we wont be able to call the next val upon it
pclndNextNode = pclndCurrentNode->getNext();
// Attempt receiving data from client
nRecvLen = recv(clntCurrentClient.getClientSocket(), pcBuffer, nRecvbuflen, 0);
// An error has occured
if (nRecvLen <= 0)
{
nError = WSAGetLastError();
// if not a timeout error
if (nError != 10060)
{
std::cout << "Client removed" << std::endl;
// Socket error, remove connection
conAllConnections->Remove(pclndCurrentNode);
}
}
// No error has occured
else
{
//// The purpose of this part of the code is only to place a [CLIENTNAME]
//// prefix within the begining of each message
////--------------------------------////
// Get client's name length
nNameLen = clntCurrentClient.getNameLength();
nIndex = nRecvLen - 1;
// Copy the message some offset forward -- offset is (namn length + 4)
while (nIndex >= 0)
{
// Copy letter (namelen + 4) times forward
pcBuffer[nIndex + nNameLen + 4] = pcBuffer[nIndex];
// Reduce nIndex
--nIndex;
}
pcBuffer[0] = '[';
nIndex = 0;
// Place clients name within message
while (nIndex < nNameLen)
{
// + 1 for offset
pcBuffer[nIndex + 1] = (clntCurrentClient.getClientName())[nIndex];
// Increase nIndex
++nIndex;
}
pcBuffer[nIndex + 1] = ']';
pcBuffer[nIndex + 2] = ':';
pcBuffer[nIndex + 3] = ' ';
////--------------------------------////
//// No longer adding a prefix code
SendAll(pclndCurrentNode, pcBuffer, nRecvLen + nNameLen + 4);
}
// Forward current node
pclndCurrentNode = pclndNextNode;
}
}
}
////////////////////////////////////////////////////
// Connections.h
#ifndef CONNECTIONS_H
#define CONNECTIONS_H
#include "ClientNode.h"
class Connections
{
private:
// Data members
static Connections* _Instance;
int nNumOfConnections;
ClientNode* pclndFirst;
// Ctor
Connections();
public:
// Methods
void Add(Client clntNewClient);
void Remove(ClientNode* pclndClientToRemove);
int getNumOfConnections();
ClientNode* getFirst();
// Static methods
static Connections* getInstance();
};
#endif
////////////////////////////////////////////////////
// Connections.cpp
#include "Connections.h"
// Set instance to null
Connections* Connections::_Instance = NULL;
/* ------- PRIVATE CTOR -------
* [Description]: This method is the constructor of the Connections
* [Paramaters]: none
* [Return Value]: none
*/
Connections::Connections()
{
this->nNumOfConnections = 0;
this->pclndFirst = NULL;
}
/*
* [Description]: This method returns the amount of connections currently within our linked list
* [Paramaters]: none
* [Return Value]: The amount of connections
*/
int Connections::getNumOfConnections(){
return (this->nNumOfConnections);
}
/*
* [Description]: This method returns a pointer to the first client node within our connection list
* [Paramaters]: none
* [Return Value]: A pointer to the first client node
*/
ClientNode* Connections::getFirst()
{
return (this->pclndFirst);
}
/*
* [Description]: This method adds a new client to the linkedlist of clients
* [Paramaters]:
* clntNewClient - The new client struct
* [Return Value]: none
*/
void Connections::Add(Client clntNewClient)
{
// Create a new client node
ClientNode* pclndNewClientNode = new ClientNode;
// Set the client node's client
pclndNewClientNode->setClient(clntNewClient);
// Set the client node's next client pointer to point at the currenly first address
pclndNewClientNode->setNext(this->getFirst());
// Set the first client pointer to point at the new client node's address ( Push it within the linked list )
this->pclndFirst = pclndNewClientNode;
// Increase the number of connection
++(this->nNumOfConnections);
}
/*
* [Description]: This method removes a client from our linked list of connections
* [Paramaters]:
* pclndClientToRemove - The address of the client node we wish to remove
* [Return Value]: none
*/
void Connections::Remove(ClientNode* pclndClientToRemove){
// Variable definition
int nIndex;
ClientNode* pclndCurrentNode;
// Code section
pclndCurrentNode = this->getFirst();
// Checking if we need to remove the first node
if (pclndCurrentNode == pclndClientToRemove)
{
// Jump over deleted node
this->pclndFirst = pclndClientToRemove->getNext();
// Free memory
delete pclndClientToRemove;
// Decrease amount of connections
--(this->nNumOfConnections);
}
// We do not need to remove the first one
else
{
// Go through all ClientNodes addresses
for (nIndex = 0; nIndex < (this->nNumOfConnections - 1); ++nIndex)
{
// If the next node is the node we wish to delete
if (pclndCurrentNode->getNext() == pclndClientToRemove)
{
// Set the current node next node to be the next node of the node we wish to delete
pclndCurrentNode->setNext(pclndClientToRemove->getNext());
// free dynamically allocated memory
delete pclndClientToRemove;
// break outside the loop
break;
// Decrease amount of connections
--(this->nNumOfConnections);
}
// Next node is not the node we whish to delete
else
{
// Move to the next node
pclndCurrentNode = pclndCurrentNode->getNext();
}
}
}
}
/*
* [Description]: This method returns the only instance of Connections (SINGLETON PATTERN)
* [Paramaters]: none
* [Return Value]: A pointer to the single instance of connection
*/
Connections* Connections::getInstance(){
// If instance was not instantiated yet
if (_Instance == NULL)
{
// Call CTOR
_Instance = new Connections();
}
return (_Instance);
}
////////////////////////////////////////////////////
// ClientNode.h
#ifndef CLIENTNODE_H
#define CLIENTNODE_H
#include "Client.h"
class ClientNode
{
// Data members
Client clntClient;
ClientNode* pclntNextClient;
public:
// Access methods
void setNext(ClientNode* pclndNextNode);
void setClient(Client clntNewClient);
Client getClient();
ClientNode* getNext();
};
#endif
////////////////////////////////////////////////////
// ClientNode.cpp
#include "ClientNode.h"
/*
* [Description]: This method sets the next node our node would be pointing add
* [Paramaters]:
* pclndNextNode - The address of the next node we want this node to point at
* [Return Value]: none
*/
void ClientNode::setNext(ClientNode* pclndNextNode)
{
this->pclntNextClient = pclndNextNode;
}
/*
* [Description]: This method sets the client struct we want our current node to contain
* [Paramaters]:
* clntNewClient - New client
* [Return Value]: none
*/
void ClientNode::setClient(Client clntNewClient)
{
this->clntClient = clntNewClient;
}
/*
* [Description]: This method returns the client instance our node contains
* [Paramaters]: none
* [Return Value]: Our client
*/
Client ClientNode::getClient()
{
return (this->clntClient);
}
/*
* [Description]: This method returns the next node our node points at
* [Paramaters]: none
* [Return Value]: The address of the next node this node is pointing at
*/
ClientNode* ClientNode::getNext()
{
return (this->pclntNextClient);
}
////////////////////////////////////////////////////
// Client.h
#ifndef CLIENT_H
#define CLIENT_H
#include <WinSock2.h>
#define MAX_CLIENT_NAME_LEN = 40
class Client
{
// Data members
SOCKET scktClientSock;
char* szClientName;
bool bIsAdmin;
int nNameLength;
public:
// Access methods
void setClientSocket(SOCKET scktClientSock);
SOCKET getClientSocket();
void setClientName(char* szClientName);
char* getClientName();
void setIsAdmin(bool bIsAdmin);
bool getIsAdmin();
int getNameLength();
// Other methods
};
#endif
////////////////////////////////////////////////////
// Client.h
#include "Client.h"
/*
* [Description]: This method changes the SOCKET data member of the Client class
* [Paramaters]:
* _scktClientSock - the new socket client that is being set
* [Return Value]: none
*/
void Client::setClientSocket(SOCKET _scktClientSock)
{
this->scktClientSock = _scktClientSock;
}
/*
* [Description]: This method retrieves the client's socket
* [Paramaters]: none
* [Return Value]: The socket client
*/
SOCKET Client::getClientSocket()
{
return (this->scktClientSock);
}
/*
* [Description]: This method changes the client's name
* [Paramaters]:
* _szClientName - a zero terminated string that describes the new client's name
* [Return Value]: none
*/
void Client::setClientName(char* _szClientName)
{
// Variable definition
int nIndex = -1;
// Code section
this->szClientName = new char[41];
// Copy string char per char
do
{
++nIndex;
this->szClientName[nIndex] = _szClientName[nIndex];
} while (_szClientName[nIndex] != '\0');
// Name length is equal to index
this->nNameLength = nIndex;
}
/*
* [Description]: This method returns a pointer to the first char of the zero terminated client string
* [Paramaters]: none
* [Return Value]: a pointer to the string
*/
char* Client::getClientName()
{
return (this->szClientName);
}
/*
* [Description]: This method is used to set whether the client is an admin or not
* [Paramaters]:
* _bIsAdmin - a boolean indication of whether the user is an admin or not
* [Return Value]: none
*/
void Client::setIsAdmin(bool _bIsAdmin)
{
this->bIsAdmin = _bIsAdmin;
}
/*
* [Description]: This method determines whether the user is an admin or not
* [Paramaters]: none
* [Return Value]: A boolean indication of whether the user is an admin or not
*/
bool Client::getIsAdmin()
{
return (this->bIsAdmin);
}
/*
* [Description]: This method retrieves the client's name length
* [Paramaters]: none
* [Return Value]: the name length
*/
int Client::getNameLength()
{
return (this->nNameLength);
}
Again this is some really old code I've wrote I apologize if it's not so good but It definitely works... also notice that I've contains many different models within the server code, each are seperated by the following
////////////////////////////////////////////////////

C code to get the interface name for the IP address in Linux

How can I get the interface name for the IP address in linux from C code ?
e.g. I'd like to get the interface name ( like etho , eth1 , l0 ) assigned for the IP address 192.168.0.1
Using /proc/net/arp you can match it. Here is a command line tool example.
usage: getdevicebyip 192.168.0.1
#include <stdio.h>
#include <fcntl.h>
int main(int argc, char **argv){
if (argc < 2) return 1;
FILE *fp = fopen("/proc/net/arp", "r");
char ip[99], hw[99], flags[99], mac[99], mask[99], dev[99], dummy[99];
fgets(dummy, 99, fp); //header line
while (fscanf(fp, "%s %s %s %s %s %s\n", ip, hw, flags, mac, mask, dev) != EOF)
if (!strcmp(argv[1],ip))
printf("%s\n",dev);
return 0;
}
You can use getifaddrs. See man 3 getifaddrs for usage information. This will only work on a Unix-like systems.
netlink is a way to do this on Linux. I think it might even be a proper way to do it on Linux (even though it isn't portable).
The strategy is:
Get a list of addresses on interfaces from the kernel by sending a netlink message.
Find the address you want (I have hard coded the one I want as address_dq) and record its interface (a number at this stage)
Get a list of interfaces by sending another netlink message,
Find the number of the interface matching the number you recorded in step (2).
Get the name of the interface.
The code below is not pretty, but I'm sure you could do a better job of it. I have been a especially sloppy by not checking for a multipart message (checking for the NLM_F_MULTI flag and for a message type of NLMSG_DONE is the way to do it). Instead I have just assumed the response to the first message is multipart -- it is on my machine -- and chewed up the NLMSG_DONE message which follows.
Code...
#include <asm/types.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <sys/socket.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, void ** argv) {
// This is the address we want the interface name for,
// expressed in dotted-quad format
char * address_dq = "127.0.0.1";
// Convert it to decimal format
unsigned int address;
inet_pton(AF_INET, address_dq, &address);
char buf[16384];
// Our first message will be a header followed by an address payload
struct {
struct nlmsghdr nlhdr;
struct ifaddrmsg addrmsg;
} msg;
// Our second message will be a header followed by a link payload
struct {
struct nlmsghdr nlhdr;
struct ifinfomsg infomsg;
} msg2;
struct nlmsghdr *retmsg;
// Set up the netlink socket
int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
// Fill in the message
// NLM_F_REQUEST means we are asking the kernel for data
// NLM_F_ROOT means provide all the addresses
// RTM_GETADDR means we want address information
// AF_INET means limit the response to ipv4 addresses
memset(&msg, 0, sizeof(msg));
msg.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
msg.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
msg.nlhdr.nlmsg_type = RTM_GETADDR;
msg.addrmsg.ifa_family = AF_INET;
// As above, but RTM_GETLINK means we want link information
memset(&msg2, 0, sizeof(msg2));
msg2.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
msg2.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
msg2.nlhdr.nlmsg_type = RTM_GETLINK;
msg2.infomsg.ifi_family = AF_UNSPEC;
// Send the first netlink message
send(sock, &msg, msg.nlhdr.nlmsg_len, 0);
int len;
// Get the netlink reply
len = recv(sock, buf, sizeof(buf), 0);
retmsg = (struct nlmsghdr *)buf;
// Loop through the reply messages (one for each address)
// Each message has a ifaddrmsg structure in it, which
// contains the prefix length as a member. The ifaddrmsg
// structure is followed by one or more rtattr structures,
// some of which (should) contain raw addresses.
while NLMSG_OK(retmsg, len) {
struct ifaddrmsg *retaddr;
retaddr = (struct ifaddrmsg *)NLMSG_DATA(retmsg);
int iface_idx = retaddr->ifa_index;
struct rtattr *retrta;
retrta = (struct rtattr *)IFA_RTA(retaddr);
int attlen;
attlen = IFA_PAYLOAD(retmsg);
char pradd[128];
// Loop through the routing information to look for the
// raw address.
while RTA_OK(retrta, attlen) {
if (retrta->rta_type == IFA_ADDRESS) {
// Found one -- is it the one we want?
unsigned int * tmp = RTA_DATA(retrta);
if (address == *tmp) {
// Yes!
inet_ntop(AF_INET, RTA_DATA(retrta), pradd, sizeof(pradd));
printf("Address %s ", pradd);
// Now we need to get the interface information
// First eat up the "DONE" message waiting for us
len = recv(sock, buf, sizeof(buf), 0);
// Send the second netlink message and get the reply
send(sock, &msg2, msg2.nlhdr.nlmsg_len, 0);
len = recv(sock, buf, sizeof(buf), 0);
retmsg = (struct nlmsghdr *)buf;
while NLMSG_OK(retmsg, len) {
struct ifinfomsg *retinfo;
retinfo = NLMSG_DATA(retmsg);
if (retinfo->ifi_index == iface_idx) {
retrta = IFLA_RTA(retinfo);
attlen = IFLA_PAYLOAD(retmsg);
char prname[128];
// Loop through the routing information
// to look for the interface name.
while RTA_OK(retrta, attlen) {
if (retrta->rta_type == IFLA_IFNAME) {
strcpy(prname, RTA_DATA(retrta));
printf("on %s\n", prname);
exit(EXIT_SUCCESS);
}
retrta = RTA_NEXT(retrta, attlen);
}
}
retmsg = NLMSG_NEXT(retmsg, len);
}
}
}
retrta = RTA_NEXT(retrta, attlen);
}
retmsg = NLMSG_NEXT(retmsg, len);
}
}
When run as above, returns Address 127.0.0.1 on lo.
Using "192.168.1.x" instead of "127.0.0.1" it instead returns Address 192.168.1.x on eth0.

Resources