Commit b73f8f8b authored by Mathias Haage's avatar Mathias Haage
Browse files

Merge branch 'sven/C-camera-master' into wip2017

parents 1fec5574 814e49d3
......@@ -73,6 +73,9 @@ static pthread_cond_t global_cond = PTHREAD_COND_INITIALIZER;
#ifdef USE_CAMERA
/* try to open capture interface.
* returns 0 on success
*/
int try_open_camera(struct global_state* state)
{
state->cam = camera_open();
......@@ -158,6 +161,9 @@ int client_send_frame(struct client* client, frame* fr)
return result;
}
/* get frame from camera and send to client
* returns zero on success
*/
int try_get_frame(struct client* client)
{
int result=-1;
......@@ -276,12 +282,17 @@ void* serve_client(void *ctxt)
return (void*) (intptr_t) close(client->connfd);
}
/* signal the global condition variable
*/
void signal_to_bg_task()
{
pthread_mutex_lock(&global_mutex);
pthread_cond_broadcast(&global_cond);
pthread_mutex_unlock(&global_mutex);
}
/* set flags to signal shutdown and
* signal global condition variable
*/
void server_quit(struct global_state* s)
{
printf("Quitting\n");
......@@ -355,10 +366,11 @@ int try_accept(struct global_state* state, struct client* client)
#ifdef INFO
printf("accepted connection\n");
#endif
// serve clients in separate thread, for three reasons
// serve clients in separate thread, for four reasons
// 1. Illustrate threading
// 2. Not blocking the user interface while serving client
// 3. Prepare for serving multiple clients concurrently
// 4. The AXIS software requires capture to be run outside the main thread
if (pthread_create(&state->client_thread, 0, serve_client, client)) {
printf("Error pthread_create()\n");
perror("creating");
......@@ -423,8 +435,8 @@ static void join_bg_thread(pthread_t* bg_thread, const char* msg)
static void client_init(struct client* client)
{
client->cam=0;
client->connfd=0;
client->cam=NULL;
client->connfd=-1;
}
int serve_clients(struct global_state* state)
{
......@@ -455,7 +467,7 @@ int serve_clients(struct global_state* state)
if(ret <0) {
perror("poll");
result = errno;
goto failed_poll;
server_quit(state);
} else if (is_running(state)) {
if(try_accept(state, client)) {
perror("try_accept");
......@@ -463,7 +475,6 @@ int serve_clients(struct global_state* state)
server_quit(state);
};
}
failed_poll:
free(client);
}
failed_to_alloc_client:
......@@ -473,11 +484,11 @@ failed_to_alloc_client:
void init_global_state(struct global_state* state)
{
pthread_mutex_lock(&global_mutex);
pthread_mutex_lock(&global_mutex);
state->running=0;
state->quit=0;
state->cam=NULL;
pthread_mutex_unlock(&global_mutex);
pthread_mutex_unlock(&global_mutex);
}
int is_running(struct global_state* state)
......@@ -509,6 +520,9 @@ int create_socket(struct global_state* state)
return 0;
}
/* bind state->listenfd to port and listen
* returns 0 on success
*/
int bind_and_listen(struct global_state* state, int port)
{
struct sockaddr_in serv_addr;
......
......@@ -24,7 +24,7 @@ static void motion_get();
int running=1;
int motionfd=0;
int motionfd=-1;
struct hostent *motion_server;
struct sockaddr_in motion_serv_addr;
......
......@@ -104,10 +104,6 @@ struct client{
static int client_write_string(struct client* client);
/////////////// client stuff
struct client;
pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t global_cond = PTHREAD_COND_INITIALIZER;
......@@ -486,20 +482,19 @@ int serve_clients(struct global_state* state)
result = errno;
};
}
failed_poll:
;
}
failed_poll:
return result;
}
void init_global_state(struct global_state* state)
{
pthread_mutex_lock(&global_mutex);
pthread_mutex_lock(&global_mutex);
state->running=0;
state->quit=0;
state->t_local=0;
state->t_remote=0;
pthread_mutex_unlock(&global_mutex);
pthread_mutex_unlock(&global_mutex);
}
int create_socket(struct global_state* state)
......
# Introduction to socket programming in C
This mimimal example consists of two pars of files for TCP and UDP:
a server which replies with a message to the first client that
connects and then exits, and a client which connects to a server and
outputs whatever it receives. (In the UDP case, the client sends a
datagram and the server echoes it back, as there is no connection
established, so the "client" must start by sending a datagram.
Note that the terms "client" and "server" in the UDP case have a
more vague meaning, where the "client" is the one that takes the initiative
by sending the first datagram.)
See "Socket programming in C" for more details.
To build and run the example, do `make run`. See the Makefile for details
An alternative to using simple_tcp_client is to use the telnet program to
connect to the server. To do that, start `simple_tcp_server` in one terminal,
and then type `telnet localhost 5000` in another.
Sometimes, `telnet` is a useful tool to look at or debug text-based protocols
over TCP.
Please note that TCP is connection-based, but not UDP. Thus, when using
UDP, there is nothing like `listen()` or `accept()`. Instead, you simply
send datagrams using `sendto()` or `sendmsg()`, and receive datagrams
with `recvfrom()` or `recvmsg()`. See the manual pages for further information.
/*
A minimal example of a TCP client
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#ifndef SERVER_PORT
#define SERVER_PORT 5000
#endif
void init(const char* server_name, int port);
static void socket_init();
static void socket_close();
static void make_request();
int sockfd=-1;
struct hostent *server;
struct sockaddr_in serv_addr;
void init(const char* server_name, int port)
{
server = gethostbyname(server_name);
if (server == NULL) {
fprintf(stderr,"ERROR, server name not found\n");
exit(1);
} else {
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
serv_addr.sin_port = htons(port);
}
}
int main(int argc, char *argv[])
{
const char* server_name;
int port;
if(argc>=2) {
server_name = argv[2];
} else {
server_name = "localhost";
}
if(argc==3) {
port = atoi(argv[3]);
} else {
port = SERVER_PORT;
}
printf("simple_tcp_client: connecting to server: %s, port %d\n",server_name, port);
init(server_name, port);
make_request();
return 0;
}
#define BUFSZ 100
static void make_request()
{
char msg[BUFSZ];
#ifdef DEBUG
printf("simple_tcp_client: connecting\n");
#endif
socket_init();
if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
perror("ERROR connecting");
} else {
int res = read(sockfd, msg, BUFSZ-1);
if(res < 0) {
perror("ERROR reading from motion server");
} else {
msg[res]='\0'; /* ensure msg is null terminated */
printf("simple_tcp_client: response: %s\n",msg);
}
socket_close();
}
}
static void socket_init()
{
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("creating motion socket");
}
}
static void socket_close()
{
if (sockfd) {
if(close(sockfd)){
perror("closing motion socket");
}
}
sockfd=-1;
}
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <string.h>
static int bind_server_socket(int fd, int port);
/*
* create a server socket bound to port
* and listening.
*
* return positive file descriptor
* or negative value on error
*/
int create_server_socket(int port)
{
int fd = -1;
if(port < 0 || port > 65535) {
errno = EINVAL;
return -1;
}
fd = socket(AF_INET,SOCK_STREAM,0);
if(fd < 0) return fd;
if(bind_server_socket(fd,port) < 0) return -1;
if(listen(fd,10)) return -1;
return fd;
}
static int bind_server_socket(int fd, int port){
struct sockaddr_in addr;
int val = 1;
if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))) {
perror("setsockopt");
return -1;
}
/* see man page ip(7) */
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
if(bind(fd, (struct sockaddr*) &addr, sizeof(addr))) return -1;
#ifdef INFO
printf("simple_tcp_server: bound fd %d to port %d\n",fd,port);
#endif
return fd;
}
/*
* Serve one client: send a message and close the socket
*/
static int do_serve(int fd)
{
int clientfd;
const char* msg = "Hello, socket!\n"
"I am a text\n"
"BYE.\n";
size_t len = strlen(msg);
printf("simple_tcp_server: attempting accept on fd %d\n",fd);
if((clientfd = accept(fd, NULL, NULL)) < 0) return -1;
#ifdef INFO
printf("simple_tcp_server: writing msg (len=%lu) to clientfd (%d)\n",len,clientfd);
#endif
#ifdef WRITE_LOOP
size_t written = 0;
do {
int res = write(clientfd, msg, len);
if (res < 0) {
perror("write to clientfd");
goto error;
}
#ifdef INFO
printf("simple_tcp_server: write returned %d\n",res);
#endif
written += res;
} while (written < len);
#else
{
int res = write(clientfd, msg, len);
if (res < 0) {
perror("write to clientfd");
goto error;
}
}
#endif
error:
printf("simple_tcp_server: closing clientfd (%d)\n",clientfd);
return close(clientfd);
}
int main()
{
int fd = create_server_socket(5000);
if(fd < 0){
perror("create_server_socket");
return 1;
}
do_serve(fd);
printf("simple_tcp_server: closing socket: %d\n", fd);
close(fd);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
#define BUFSZ 1024
#define SERVER_PORT 5000
/*
* create a datagram socket
*/
int create_socket()
{
int fd = -1;
fd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
return fd;
}
#undef USE_IP_NUMBER
static int init_remote(struct sockaddr_in* remote_end, socklen_t remote_size, const char* server_str, int port )
{
memset((char*) &remote_end, 0, remote_size);
remote_end->sin_family = AF_INET;
remote_end->sin_port = htons(port);
#ifdef USE_IP_NUMBER
if (inet_aton(server_str , &remote_end->sin_addr) == 0)
{
fprintf(stderr, "inet_aton() failed\n");
return -1;
}
#else
{
struct hostent* server;
server = gethostbyname(server_str);
if (server == NULL) {
fprintf(stderr,"ERROR, server name not found\n");
return -1;
} else {
bcopy((char *)server->h_addr, (char *)&remote_end->sin_addr.s_addr, server->h_length);
}
}
#endif
}
/*
* Send a datagram to server and wait for one reply
*/
static int send_and_receive(int fd, const char* server_str, int port)
{
char buf[BUFSZ];
struct sockaddr_in remote_end;
socklen_t remote_size = sizeof(remote_end);
if(port < 0 || port > 65535) {
errno = EINVAL;
return -1;
}
printf("simple_udp_client: sending to %s:%d (fd=%d)\n",server_str,port,fd);
init_remote(&remote_end, remote_size, server_str, port);
const char* msg = "Hello, socket!\n"
"I am a text\n"
"BYE.\n";
ssize_t len = strlen(msg);
len = sendto(fd, msg, len, 0, (struct sockaddr*) &remote_end, remote_size);
if(len == -1){
perror("sendto");
return len;
}
printf("simple_udp_client: waiting for datagram on fd %d\n",fd);
len = recvfrom(fd, buf, BUFSZ-1, 0, (struct sockaddr*) &remote_end, &remote_size);
if(len == -1){
perror("recvfrom");
return len;
}
buf[len] = 0; /* add null termination to string*/
printf("simple_udp_client: received packet from %s:%d, len=%zu\n%s\n",
inet_ntoa(remote_end.sin_addr),
ntohs(remote_end.sin_port),
len,
buf);
return 0;
}
int main(int argc, char *argv[])
{
const char* server_str;
int port;
int fd;
if(argc>=2) {
server_str = argv[1];
} else {
#ifdef USE_IP_NUMBER
server_str = "127.0.0.1";
#else
server_str = "localhost";
#endif
}
if(argc==3) {
port = atoi(argv[2]);
} else {
port = SERVER_PORT;
}
// printf("simple_client: connecting to server: %s, port %d\n",server_str, port);
fd = create_socket();
if(fd < 0){
perror("create_socket");
return 1;
}
printf("calling send_and_receive for %s,%d\n",server_str,port);
send_and_receive(fd, server_str, port);
printf("simple_udp_client: closing socket: %d\n", fd);
close(fd);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>
#define BUFSZ 1024
#define SERVER_PORT 5000
static int bind_socket(int fd, int port);
/*
* create a server socket bound to port
* and listening.
*
* return positive file descriptor
* or negative value on error
*/
int create_socket(int port)
{
int fd = -1;
if(port < 0 || port > 65535) {
errno = EINVAL;
return -1;
}
fd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if(fd < 0) return fd;
if(bind_socket(fd,port) < 0) return -1;
printf("simple_udp_server: bound socket to port %d\n",port);
return fd;
}
static int bind_socket(int fd, int port){
struct sockaddr_in addr;
// if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))) {
// perror("setsockopt");
// return -1;
// }
/* see man page ip(7) */
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(fd, (struct sockaddr*) &addr, sizeof(addr))) return -1;
#ifdef INFO
printf("simple_server: bound fd %d to port %d\n",fd,port);
#endif
return fd;
}
/*
* Wait for one datagram and echo it back
*/
static int do_serve(int fd)
{
char buf[BUFSZ];
struct sockaddr_in remote_end;
socklen_t remote_size = sizeof(remote_end);
// const char* msg = "Hello, socket!\n"
// "I am a text\n"
// "BYE.\n";
// size_t len = strlen(msg);
ssize_t len;
printf("simple_server: waiting for datagram on fd %d\n",fd);
len = recvfrom(fd, buf, BUFSZ-1, 0, (struct sockaddr*) &remote_end, &remote_size);
if(len == -1){
perror("recvfrom");
return len;
}
buf[len] = 0; /* add null termination to string*/