pixelserver2/apps/c-src/pixelflut.c

249 lines
6.7 KiB
C
Raw Normal View History

2018-12-30 14:27:43 +00:00
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <assert.h>
2018-12-31 12:47:21 +00:00
#include <ctype.h>
#include <stdio.h>
2024-10-28 17:10:03 +00:00
#include <pthread.h>
2018-12-31 12:47:21 +00:00
#include <stdlib.h>
2018-12-30 14:27:43 +00:00
int Nx, Ny;
2018-12-31 12:47:21 +00:00
int port;
2018-12-30 14:27:43 +00:00
uint8_t *buf;
2018-12-31 12:47:21 +00:00
void SetPixelRGB(int x, int y, uint8_t r, uint8_t g, uint8_t b){
2018-12-30 14:27:43 +00:00
if (x < 0 || x >= Nx || y < 0 || y >= Ny) return;
buf[3*(x+Nx*y)+0] = r;
buf[3*(x+Nx*y)+1] = g;
buf[3*(x+Nx*y)+2] = b;
}
void SetPixel(int x, int y, uint32_t c){
2018-12-31 12:47:21 +00:00
SetPixelRGB(x, y, (c >> 16)&0xff, (c >> 8)&0xff, c&0xff);
2018-12-30 14:27:43 +00:00
}
uint32_t GetPixel(int x, int y){
if (x < 0 || x >= Nx || y < 0 || y >= Ny) return 0;
uint32_t r = buf[3*(x+Nx*y)+0];
uint32_t g = buf[3*(x+Nx*y)+1];
uint32_t b = buf[3*(x+Nx*y)+2];
return (r << 16) | (g << 8) | b;
}
static const int PFT_CONNECTION_TIMEOUT = 1;
volatile int PFT_ClientThreadCount = 0;
2018-12-31 12:47:21 +00:00
int PFT_ReadIdent(char** begin, char* end, char* out, int size){
2018-12-30 14:27:43 +00:00
int i = 0;
while (*begin != end && isalpha(**begin) && i < size-1){
out[i++] = **begin;
(*begin)++;
}
out[i] = '\0';
return i != 0;
}
2018-12-31 12:47:21 +00:00
int PRF_ReadInt(char** begin, char* end, int *out){
2018-12-30 14:27:43 +00:00
if (*begin == end || !isdigit(**begin))
2018-12-31 12:47:21 +00:00
return 0;
2018-12-30 14:27:43 +00:00
*out = 0;
while(*begin != end && isdigit(**begin)){
*out = (*out)*10+(**begin-'0');
(*begin)++;
}
2018-12-31 12:47:21 +00:00
return 1;
2018-12-30 14:27:43 +00:00
}
2018-12-31 12:47:21 +00:00
int PFT_IsHex(char c){
2018-12-30 14:27:43 +00:00
return isdigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}
int PFT_HexCharToInt(char c){
if (isdigit(c))
return c-'0';
if (c >= 'a' && c <= 'f')
return c-'a'+10;
if (c >= 'A' && c <= 'F')
return c-'A'+10;
return 0;
}
2018-12-31 12:47:21 +00:00
int PFT_ReadColorHex(char** begin, char* end, uint32_t *out){
2018-12-30 14:27:43 +00:00
char* oldbegin = *begin;
*out = 0;
if (end-*begin < 6)
2018-12-31 12:47:21 +00:00
return 0;
2018-12-30 14:27:43 +00:00
for(int i = 0; i != 6; i++){
if (!PFT_IsHex(**begin)){
*begin = oldbegin;
2018-12-31 12:47:21 +00:00
return 0;
2018-12-30 14:27:43 +00:00
}
*out = (*out)*16+PFT_HexCharToInt(**begin);
(*begin)++;
}
if (end-*begin >= 2 && PFT_IsHex(**begin) && PFT_IsHex(begin[0][1])){
*out = (*out)*16+PFT_HexCharToInt(**begin);
(*begin)++;
*out = (*out)*16+PFT_HexCharToInt(**begin);
(*begin)++;
}else{
*out *= 256;
}
2018-12-31 12:47:21 +00:00
return 1;
2018-12-30 14:27:43 +00:00
}
void PFT_SkipSpace(char **begin, char *end){
while(*begin != end && **begin == ' '){
(*begin)++;
}
}
void PFT_SkipOverNextNewline(char **begin, char *end){
while(*begin != end && **begin != '\n'){
(*begin)++;
}
if (*begin != end)
(*begin)++;
}
int PFT_HandlePixelflutMessage(uint8_t *buffer, int size, int sock){
char *begin = (char*)buffer;
char *end = begin + size;
char cmd_buffer[32];
char response_buffer[100];
int x, y;
uint32_t c;
//packet_size = MIN(offset + (pixellength * MAX_PIXELS), packet_size);
while ( begin != end ) {
if (!PFT_ReadIdent(&begin, end, cmd_buffer, 32)){
PFT_SkipOverNextNewline(&begin, end);
continue;
}
if (strcmp(cmd_buffer, "PX") == 0){
PFT_SkipSpace(&begin, end);
if (!PRF_ReadInt(&begin, end, &x)){
PFT_SkipOverNextNewline(&begin, end);
continue;
}
PFT_SkipSpace(&begin, end);
if (!PRF_ReadInt(&begin, end, &y)){
PFT_SkipOverNextNewline(&begin, end);
continue;
}
PFT_SkipSpace(&begin, end);
if (PFT_ReadColorHex(&begin, end, &c)){
SetPixel(x, y, c>>8);
}else{
c = GetPixel(x, y);
int len = sprintf(response_buffer, "PX %i %i %06x\n", x, y, c);
send(sock, response_buffer, len, 0);
}
}
else if (strcmp(cmd_buffer, "SIZE") == 0){
int len = sprintf(response_buffer, "SIZE %i %i", Nx, Ny);
send(sock, response_buffer, len, 0);
}
else if (strcmp(cmd_buffer, "HELP") == 0){
int len = sprintf(response_buffer, "see https://github.com/defnull/pixelflut\n");
send(sock, response_buffer, len, 0);
}
PFT_SkipOverNextNewline(&begin, end);
}
return begin-(char*)buffer;
}
2024-10-28 17:10:03 +00:00
void* PFT_HandleClient(void* sock_){
2018-12-31 12:47:21 +00:00
int sock = (int)(size_t)sock_;
2018-12-30 14:27:43 +00:00
PFT_ClientThreadCount++;
uint8_t buf[1024];
uint8_t offset = 0;
int read_size = 0;
while( (read_size = recv(sock , buf + offset, sizeof(buf) - offset , 0)) > 0){
offset = PFT_HandlePixelflutMessage(buf, read_size, sock);
memcpy(buf, buf+read_size-offset, offset);
}
close(sock);
PFT_ClientThreadCount--;
return 0;
}
2024-10-28 17:10:03 +00:00
void* PFT_RunServer(void* _){
2018-12-30 14:27:43 +00:00
int client_sock;
socklen_t addr_len;
struct sockaddr_in addr;
addr_len = sizeof(addr);
struct timeval tv;
fprintf(stderr, "PF: Starting Pixelflut Server...\n");
int server_sock = socket(PF_INET, SOCK_STREAM, 0);
tv.tv_sec = PFT_CONNECTION_TIMEOUT;
tv.tv_usec = 0;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons(port);
addr.sin_family = AF_INET;
if (server_sock == -1){
fprintf(stderr, "PF: socket() failed\n");
return 0;
}
int one = 1;
if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int)) < 0)
fprintf(stderr, "PF: setsockopt(SO_REUSEADDR) failed\n");
if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(int)) < 0)
fprintf(stderr, "PF: setsockopt(SO_REUSEPORT) failed\n");
int retries;
for (retries = 0; bind(server_sock, (struct sockaddr*)&addr, sizeof(addr)) == -1 && retries < 10; retries++){
fprintf(stderr, "PF: bind() failed ...retry in 5s\n");
usleep(5000000);
}
if (retries == 10)
return 0;
if (listen(server_sock, 4) == -1){
fprintf(stderr, "PF: listen() failed\n");
return 0;
}
fprintf(stderr, "PF: Pixelflut Listening...\n");
setsockopt(server_sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv,sizeof(struct timeval));
setsockopt(server_sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv,sizeof(struct timeval));
2018-12-31 12:47:21 +00:00
while(1){
2018-12-30 14:27:43 +00:00
client_sock = accept(server_sock, (struct sockaddr*)&addr, &addr_len);
if(client_sock > 0){
2024-10-28 17:10:03 +00:00
pthread_t thread;
pthread_create(&thread, NULL, PFT_HandleClient, (void*)(size_t)client_sock);
pthread_detach(thread);
2018-12-30 14:27:43 +00:00
}
}
close(server_sock);
return 0;
}
int main(int argc, char **argv) {
Nx = atoi(argv[1]);
Ny = atoi(argv[2]);
buf = (uint8_t*)malloc(Nx*Ny*3);
2018-12-31 12:47:21 +00:00
port = atoi(argv[3]);
2018-12-30 14:27:43 +00:00
if (port == 0) port = 4444;
2024-10-28 17:10:03 +00:00
pthread_t thread;
pthread_create(&thread, NULL, PFT_RunServer, NULL);
2018-12-30 14:27:43 +00:00
while(1) {
write(1, buf, Nx*Ny*3);
usleep(33*1000);
}
2024-10-28 17:10:03 +00:00
}