/* * $Logfile: /DescentIII/Main/linux/lnxmono.cpp $ * $Revision: 1.3 $ * $Date: 2004/02/23 03:03:48 $ * $Author: ryan $ * * Linux monochrome routines * * $Log: lnxmono.cpp,v $ * Revision 1.3 2004/02/23 03:03:48 ryan * Patched to compile with gcc3 and a modern linux distro... * * Revision 1.2 2000/05/29 05:39:59 icculus * Changed some exit() calls to _exit(). * * Revision 1.1.1.1 2000/04/18 00:00:39 icculus * initial checkin * * * 13 8/22/99 5:52a Jeff * remote monochrome server code added * * 12 7/14/99 9:09p Jeff * added comment header * * $NoKeywords: $ */ #include "debug.h" #include #include #include #include #include #include #include #include #include // -------- Start TCP/IP Mono Logging Section #include #include #include #include #include #include #include #include #define MAX_TCPLOG_LEN 2000 #define SOCKET int #define SOCKADDR_IN sockaddr_in #define SOCKADDR sockaddr #define INVALID_SOCKET -1 static SOCKET tcp_log_sock; static struct sockaddr_in tcp_log_addr; static char tcp_log_buffer[MAX_TCPLOG_LEN]; static int Console_fd = -1; static bool Mono_initialized = 0; static bool Mono_use_real = false; static bool Mono_use_window_remote = false; static int Debug_logfile = 0; bool Debug_print_block = false; #define min(a, b) ((a < b) ? a : b) // =============================== // pthread library functions // =============================== #include #include #if DLOPEN_PTHREAD typedef int (*pthread_create_fp)(pthread_t *__thread, __const pthread_attr_t *__attr, void *(*__start_routine)(void *), void *__arg); typedef int (*pthread_detach_fp)(pthread_t __th); typedef pthread_t (*pthread_self_fp)(void); static pthread_create_fp dpthread_create = NULL; static pthread_detach_fp dpthread_detach = NULL; static pthread_self_fp dpthread_self = NULL; #else #define dpthread_create pthread_create #define dpthread_detach pthread_detach #define dpthread_self pthread_self #endif static unsigned long long Timer_sys_start_time = 0; static unsigned long long Timer_accum = 0, Timer_high_mark = 0; static float nw_TCPLoggingTimer(void) { unsigned long time_ms; unsigned long long ret; struct timeval t; gettimeofday(&t, NULL); ret = (unsigned long long)t.tv_sec * 1000000.0 + t.tv_usec; if (ret > Timer_high_mark) { Timer_high_mark = ret; } else { // timer roll over if (Timer_high_mark > 0) Timer_accum += (Timer_high_mark - Timer_sys_start_time); Timer_high_mark = ret; Timer_sys_start_time = ret; ret = 100; // give some time } time_ms = Timer_accum + ret - Timer_sys_start_time; return (float)((double)time_ms / ((double)1000000.0)); } static bool nw_TCPLoggingTimer_Init(void) { struct timeval t; gettimeofday(&t, NULL); Timer_sys_start_time = (unsigned long long)t.tv_sec * 1000000.0 + t.tv_usec; Timer_accum = 0; Timer_high_mark = 0; return true; } static unsigned char outgoing_mono_packet[512]; static volatile int outgoing_packet_size = 0; static volatile float outgoing_last_time_sent = 0; static volatile bool outgoing_packet_flush = false; static volatile bool outgoing_building_packet = false; void *nw_TCPLoggingWorker(void *arg) { dpthread_detach(dpthread_self()); while (1) { if (tcp_log_sock == INVALID_SOCKET) break; fd_set wfds; timeval timeout = {0, 0}; FD_ZERO(&wfds); FD_SET(tcp_log_sock, &wfds); int sock_writable = select(tcp_log_sock + 1, NULL, &wfds, NULL, &timeout); if (sock_writable == -1) { fprintf(stdout, "Error blocking on Monochrome server port\n"); _exit(1); } if (!sock_writable) { continue; } if (outgoing_packet_size == 0) continue; if (outgoing_building_packet) continue; int save_size = outgoing_packet_size; outgoing_packet_size = -1; // this informs the other thread that we are sending float curr_time = nw_TCPLoggingTimer(); if (curr_time > (outgoing_last_time_sent + 0.05f)) { // time to send the packet outgoing_last_time_sent = curr_time; send(tcp_log_sock, outgoing_mono_packet, save_size, 0); save_size = 0; } outgoing_packet_size = save_size; } return NULL; } bool nw_InitTCPLogging(char *ip, unsigned short port) { #if DLOPEN_PTHREAD // load up the pthread library void *lib = dlopen("libpthread.so", RTLD_GLOBAL | RTLD_NOW); if (!lib) { fprintf(stdout, "Error: Unable to load libpthread.so\n"); _exit(1); } dpthread_create = (pthread_create_fp)dlsym(lib, "pthread_create"); dpthread_detach = (pthread_detach_fp)dlsym(lib, "pthread_detach"); dpthread_self = (pthread_self_fp)dlsym(lib, "pthread_self"); #endif unsigned long argp = 1; int addrlen = sizeof(SOCKADDR_IN); tcp_log_sock = socket(AF_INET, SOCK_STREAM, 0); if (INVALID_SOCKET == tcp_log_sock) { return false; } memset(&tcp_log_addr, 0, sizeof(SOCKADDR_IN)); tcp_log_addr.sin_family = AF_INET; tcp_log_addr.sin_addr.s_addr = INADDR_ANY; tcp_log_addr.sin_port = 0; if (bind(tcp_log_sock, (SOCKADDR *)&tcp_log_addr, sizeof(sockaddr))) { return false; } tcp_log_addr.sin_addr.s_addr = inet_addr(ip); tcp_log_addr.sin_port = htons(port); fd_set write_fs; FD_ZERO(&write_fs); FD_SET(tcp_log_sock, &write_fs); select(tcp_log_sock + 1, NULL, &write_fs, NULL, NULL); fprintf(stdout, "Connecting to monochrome server (%s:%d)...\n", ip, port); if (connect(tcp_log_sock, (SOCKADDR *)&tcp_log_addr, addrlen)) { int wserr; wserr = errno; fprintf(stdout, "Mono: Connect Failed..."); switch (wserr) { case EBADF: fprintf(stdout, "EBADF\n"); break; case EFAULT: fprintf(stdout, "EFAULT\n"); break; case ENOTSOCK: fprintf(stdout, "ENOTSOCK\n"); break; case EISCONN: fprintf(stdout, "EISCONN\n"); break; case ECONNREFUSED: fprintf(stdout, "EREFUSED\n"); break; case ETIMEDOUT: fprintf(stdout, "ETIMEDOUT\n"); break; case ENETUNREACH: fprintf(stdout, "ENETUNREACH\n"); break; default: fprintf(stdout, "Unknown error %d\n", wserr); break; } return false; } fprintf(stdout, "Monochrome server connected\n"); // init the packet sent time pthread_t thread; nw_TCPLoggingTimer_Init(); outgoing_last_time_sent = nw_TCPLoggingTimer(); dpthread_create(&thread, NULL, nw_TCPLoggingWorker, NULL); return true; } void nw_TCPPrintf(int n, char *format, ...) { return; } void nw_SendMonoPacket(unsigned char *data, int size) { if (tcp_log_sock == INVALID_SOCKET) { return; } if (size > 512) { fprintf(stdout, "Mono: Packet > 512 bytes\n"); _exit(1); } outgoing_building_packet = true; while (outgoing_packet_size == -1) ; if (outgoing_packet_size + size > 512) { // crap...we need to flush fd_set wfds; FD_ZERO(&wfds); FD_SET(tcp_log_sock, &wfds); int sock_writable = select(tcp_log_sock + 1, NULL, &wfds, NULL, NULL); if (sock_writable == -1) { fprintf(stdout, "Error blocking on Monochrome server port\n"); _exit(1); } send(tcp_log_sock, outgoing_mono_packet, outgoing_packet_size, 0); outgoing_packet_size = 0; } memcpy(&outgoing_mono_packet[outgoing_packet_size], data, size); outgoing_packet_size += size; outgoing_building_packet = false; } // ---------------- End TCP/IP Mono Logging Section void Debug_LogClose(); bool Debug_Logfile(const char *filename) { if (Debug_logfile == -1) { Debug_logfile = open(filename, O_CREAT | O_WRONLY, S_IREAD | S_IWRITE); if (Debug_logfile == -1) { Debug_MessageBox(OSMBOX_OK, "Debug", "FYI Logfile couldn't be created."); return false; } atexit(Debug_LogClose); } Debug_LogWrite("BEGINNING LOG\n\n"); return true; } void Debug_LogWrite(const char *str) { if (Debug_logfile > -1) write(Debug_logfile, str, strlen(str)); } void Debug_LogClose() { if (Debug_logfile > -1) { Debug_LogWrite("\nEND LOG"); close(Debug_logfile); Debug_logfile = -1; } } // void Debug_SetSpewFilter(uint spew_filter) void Debug_SetSpewFilter(uint) {} // uint Debug_GetSpewFilter(uint spew_filter) uint Debug_GetSpewFilter(uint) { return 0; } void Debug_ConsoleExit() { if (Console_fd >= 0) close(Console_fd); Console_fd = -1; } #define MAX_ARGS 30 #define MAX_CHARS_PER_ARG 100 extern char GameArgs[MAX_ARGS][MAX_CHARS_PER_ARG]; int FindArg(char *which); bool Debug_ConsoleInit() { int n = 0; if (Mono_initialized) return 1; // Only use monochrome if D3_MONO environment var is set atexit(Debug_ConsoleExit); Console_fd = open("/dev/omono", O_WRONLY); if (Console_fd >= 0) { Mono_use_real = true; Mono_initialized = 1; } int arg; if ((arg = FindArg("-monotcp")) != 0) { char address[256]; strcpy(address, GameArgs[arg + 1]); char *port_ptr; port_ptr = strchr(address, ':'); if (port_ptr) { *port_ptr = '\0'; port_ptr++; unsigned short port; port = atoi(port_ptr); if (nw_InitTCPLogging(address, port)) { Mono_use_window_remote = true; Mono_initialized = 1; } } } return 1; } void Debug_ConsoleRedirectMessages(int virtual_window, int physical_window) { if (!Mono_initialized) return; /* 0x02 Redirect Messages Parameters: Offset Size Value Description ====== ==== ===== =========== 0x01 0x01 0-7 Virtual window handle to be associated with physical window 0x02 0x01 0-3 Window handle to be redirected */ // create the packet and send it off unsigned char packet[3]; packet[0x00] = 0x02; // control code packet[0x01] = virtual_window; // virtual_handle packet[0x02] = physical_window; // physical_handle // send the packet if (Mono_use_real) { write(Console_fd, packet, 3); } if (Mono_use_window_remote) { nw_SendMonoPacket(packet, 3); } } void Debug_ConsoleOpen(int n, int row, int col, int width, int height, char *title) { if (!Mono_initialized) return; /* 0x00 Open a window Parameters: Offset Size Value Description ====== ==== ===== =========== 0x01 0x01 0-3 Window handle to be associated with window 0x02 0x01 0-23 Upper left corner row value 0x03 0x01 0-78 Upper left corner col value 0x04 0x01 1-79 Number of cols (width) 0x05 0x01 1-24 Number of rows (height) 0x06 0x01 1-255 Length of the title string 0x07-> [0x06] ---- Title string (not \0 terminated) */ // create the packet and send it off unsigned char packet[512]; int len = (title) ? strlen(title) : 1; packet[0x00] = 0x00; // control code packet[0x01] = n; // window_handle packet[0x02] = row; // row packet[0x03] = col; // col packet[0x04] = width; // width packet[0x05] = height; // height packet[0x06] = len; if (title) memcpy(&packet[0x07], title, len); else packet[0x07] = ' '; // send the packet if (Mono_use_real) { write(Console_fd, packet, len + 7); } if (Mono_use_window_remote) { nw_SendMonoPacket(packet, len + 7); } } void Debug_ConsoleClose(int n) { if (!Mono_initialized) return; /* 0x01 Closes a window Parameters: Offset Size Value Description ====== ==== ===== =========== 0x01 0x01 0-3 Window handle to be associated with window */ // create the packet and send it off unsigned char packet[2]; packet[0x00] = 0x01; // control code packet[0x01] = n; // window_handle // send the packet if (Mono_use_real) { write(Console_fd, packet, 2); } if (Mono_use_window_remote) { nw_SendMonoPacket(packet, 2); } } #ifdef _DEBUG #define MAX_MONO_BUFFER 2048 #else #define MAX_MONO_BUFFER 32 #endif static char Mono_buffer[MAX_MONO_BUFFER]; void Debug_ConsolePrintf(int n, char *format, ...) { va_list marker; va_start(marker, format); int text_len = vsnprintf(Mono_buffer, MAX_MONO_BUFFER, format, marker); va_end(marker); if (n == 0) { printf("%s", Mono_buffer); int end = strlen(Mono_buffer) - 1; if ((end > 1) && (Mono_buffer[end] != 0x0a) && (Mono_buffer[end] != 0x0d)) { printf("\n"); } } nw_TCPPrintf(n, Mono_buffer); if (!Mono_initialized) return; /* 0x03 Window Print at cursor position Parameters: Offset Size Value Description ====== ==== ===== =========== 0x01 0x01 0-3 Window handle to be associated with window 0x02 0x02 0-512 (Little Endian) Length of the text string 0x04 [0x02] ---- Text string (not \0 terminated) */ // create the packet and send it off text_len = min(text_len, 512); unsigned char packet[518]; packet[0x00] = 0x03; // control code packet[0x01] = n; // window_handle *((unsigned short *)&packet[0x02]) = text_len; memcpy(&packet[0x04], Mono_buffer, text_len); // send the packet if (Mono_use_real) { write(Console_fd, packet, text_len + 4); } if (Mono_use_window_remote) { nw_SendMonoPacket(packet, text_len + 4); } } void Debug_ConsolePrintf(int n, int row, int col, char *format, ...) { if (!Mono_initialized) return; va_list marker; va_start(marker, format); int text_len = vsnprintf(Mono_buffer, MAX_MONO_BUFFER, format, marker); va_end(marker); /* 0x04 Window Print at row/col given Parameters: Offset Size Value Description ====== ==== ===== =========== 0x01 0x01 0-3 Window handle to be associated with window 0x02 0x01 0-24 Starting row (relative to window) of text 0x03 0x01 0-79 Starting col (relative to window) of text 0x04 0x02 0-512 (Little Endian) Length of the text string 0x06 [0x04] ---- Text string (not \0 terminated) */ // create the packet and send it off unsigned char packet[518]; text_len = min(text_len, 512); packet[0x00] = 0x04; // control code packet[0x01] = n; // window_handle packet[0x02] = row; // row packet[0x03] = col; // col *((unsigned short *)&packet[0x04]) = text_len; memcpy(&packet[0x06], Mono_buffer, text_len); // send the packet if (Mono_use_real) { write(Console_fd, packet, text_len + 6); } if (Mono_use_window_remote) { // we can't send these to a mono server, they flood us // nw_SendMonoPacket(packet,text_len+6); } }