So I am writing a peer-to-peer chat client that uses pthreads to manage all the IO and when I compile the file gcc gives me the error
client.c: In function ‘accepted_daemon’:
client.c:115:1: error: expected ‘while’ before ‘void’
void *
^
client.c: In function ‘listen_daemon’:
client.c:176:1: error: expected ‘while’ before ‘int’
int main(int argc, char *argv[])
^
The source code for my program is
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <errno.h>
#include <assert.h>
#include <unistd.h>
#include <pthread.h>
#include <readline/readline.h>
#include <error.h>
#define error(s, e, ...) error_at_line (s, e, __FILE__, __LINE__, __VA_ARGS__)
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#define PORT 3248
#define PROMPT "message: "
struct accepted
{
int fd;
struct sockaddr_in addr;
};
struct value
{
struct accepted *acc;
struct value *nxt;
};
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
struct value *remote = NULL;
void
push_remote (struct accepted *acc)
{
pthread_mutex_lock (&mutex);
struct value *s = malloc (sizeof *s);
s->acc = acc;
s->nxt = remote;
remote = s;
pthread_mutex_unlock (&mutex);
}
void
pop_remote (struct accepted *acc)
{
pthread_mutex_lock (&mutex);
struct value head = { NULL, remote };
struct value *s = &head;
while (s->nxt->acc != acc)
{
s = s->nxt;
if (s->nxt == NULL)
return;
}
struct value *tmp = s->nxt->nxt;
free (s->nxt);
s->nxt = tmp;
}
struct accepted *
make_socket (uint32_t s_addr)
{
struct accepted *addr = malloc (sizeof *addr);
addr->fd = socket (PF_INET, SOCK_STREAM, 0);
if (addr->fd < 0)
{
free (addr);
return NULL;
}
addr->addr.sin_family = AF_INET;
addr->addr.sin_port = htons (PORT);
addr->addr.sin_addr.s_addr = s_addr;
if (connect (addr->fd, (struct sockaddr *) &addr->addr,
sizeof addr->addr) < 0)
{
free (addr);
return NULL;
}
return addr;
}
void *
accepted_daemon (void *arg)
{
pthread_cleanup_push (free, arg);
struct accepted *args = arg;
pthread_cleanup_push (close, args->fd);
push_remote (args);
pthread_cleanup_push (pop_remote, args);
while (1)
{
char buffer[100];
ssize_t chars = read (args->fd, buffer, sizeof buffer);
if (chars < 0)
{
error (0, errno, "Host %s disconnected",
inet_ntop (AF_INET, arg, buffer, sizeof buffer));
return NULL;
}
write (1, buffer, chars);
write (1, "\n", strlen ("\n") * sizeof (char));
}
return NULL;
}
void *
initial_connection (void *arg)
{
uint32_t host = (uint32_t) arg;
struct accepted *acc = make_socket (arg);
if (acc == NULL)
{
char buffer[100];
error (1, errno, "Failed to connect to host %s",
inet_ntop (AF_INET, arg, buffer, sizeof buffer));
}
while (1)
{
uint32_t nxthost;
read (sock, &nxthost, sizeof nxthost);
if (nxthost == 0)
break;
pthread_t thread;
pthread_create (&thread, NULL, initial_connection, (void *) nxthost);
}
return accepted_daemon (acc);
}
void *
listen_daemon (void *arg)
{
int sock = socket (PF_INET, SOCK_STREAM, 0);
pthread_cleanup_push (close, sock);
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons (PORT);
addr.sin_addr.s_addr = INADDR_ANY;
bind (sock, (struct sockaddr *) &addr, sizeof addr);
listen (sock, 5);
while (1)
{
struct accepted *acc = malloc (sizeof *acc);
socklen_t len;
acc->fd = accept (sock, (struct sockaddr *) &acc->addr, &len);
pthread_mutex_lock (&mutex);
struct value *p = remote;
while (p != NULL)
{
write (acc->fd, &p->acc->addr.sin_addr.s_addr, sizeof (uint32_t));
p = p->nxt;
}
pthread_mutex_unlock (&mutex);
pthread_t thread;
pthread_create (&thread, NULL, accepted_daemon, (void *) acc);
}
return NULL;
}
int main(int argc, char *argv[])
{
assert (argc == 2);
struct hostent *target = gethostbyname2 (argv[1], AF_INET);
if (target == NULL)
error (1, errno, "Host could not be found");
pthread_t thread;
pthread_create (&thread, NULL, initial_connection,
(void *) inet_addr (target->h_addr));
pthread_create (&thread, NULL, listen_daemon, NULL);
char *in = readline (PROMPT);
while (in != NULL)
{
pthread_mutex_lock (&mutex);
struct value *p = remote;
while (p != NULL)
{
write (p->addr->fd, in, strlen (in));
p = p->nxt;
}
pthread_mutex_unlock (&mutex);
free (in);
in = readline (PROMPT);
}
return 0;
}
pthread_cleanup_push()
most likely is implemented as a macro introducing an open brace {
which expects a (corresponding) pthread_cleanup_pop()
in the same context. The latter then serves the closing brace }
. *1
Have a look at the pre-processor output of the code (and into the according man-pages and header files of course) and you'll get enlightened.
*1 This kind of implementation, BTW, is the most rigorous way I ever saw to discipline C coders ... ;->
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With