#include #include #include #include #include #include #include #include int Nx, Ny; uint8_t *buf; void SetPixel(int x, int y, uint8_t r, uint8_t g, uint8_t b){ 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){ SetPixel(x, y, (c >> 16)&0xff, (c >> 8)&0xff, c&0xff); } 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; bool PFT_ReadIdent(char** begin, char* end, char* out, int size){ int i = 0; while (*begin != end && isalpha(**begin) && i < size-1){ out[i++] = **begin; (*begin)++; } out[i] = '\0'; return i != 0; } bool PRF_ReadInt(char** begin, char* end, int *out){ if (*begin == end || !isdigit(**begin)) return false; *out = 0; while(*begin != end && isdigit(**begin)){ *out = (*out)*10+(**begin-'0'); (*begin)++; } return true; } bool PFT_IsHex(char c){ 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; assert(false); return 0; } bool PFT_ReadColorHex(char** begin, char* end, uint32_t *out){ char* oldbegin = *begin; *out = 0; if (end-*begin < 6) return false; for(int i = 0; i != 6; i++){ if (!PFT_IsHex(**begin)){ *begin = oldbegin; return false; } *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; } return true; } 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; } void * PFT_HandleClient(int sock){ 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; } void * PFT_RunServer(unsigned long port){ 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)); while(true){ client_sock = accept(server_sock, (struct sockaddr*)&addr, &addr_len); if(client_sock > 0){ std::thread client_thread(PFT_HandleClient, client_sock); client_thread.detach(); } } 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); int port = atoi(argv[3]); if (port == 0) port = 4444; std::thread pixelflut_tcp_thread(&PFT_RunServer,(unsigned long)port); while(1) { write(1, buf, Nx*Ny*3); usleep(33*1000); } }