/* Copyright 1997 Acorn Computers Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /************************************************************************/ /* Copyright 1996 Acorn Computers Ltd */ /* */ /* This material is the confidential trade secret and proprietary */ /* information of Acorn Computers. It may not be reproduced, used */ /* sold, or transferred to any third party without the prior written */ /* consent of Acorn Computers. All rights reserved. */ /* */ /************************************************************************/ #include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdlib.h> #include "sys/types.h" #include "sys/socket.h" #include "sys/time.h" #include "netdb.h" #include "netinet/in.h" #include "socklib.h" #define REMOTE_DEBUG #include "remote.h" #include "VersionNum" /* Gives the version number an extra space if there's no minor version number but I can't figure how to get the preprocessor to fix this */ static const char REMOTE_DEBUG_VERSION[] = Module_MajorVersion " " Module_MinorVersion; #define REMOTE_DEBUG_MAX_LINE (10*1024) static int poll=1; static char *debug_line = NULL; /* * compare two strings caselessly */ static int caseless_strcmp(char *a, char *b) { int d; while (*a || *b) { d = tolower( *(a++) ) - tolower( *(b++) ); if (d) return d; } return 0; } /* * check the input port for any data, if there is, check it for a newline * and if terminated correctly, extract the line. */ int debug_poll(debug_session *sess) { fd_set read_set; struct timeval tv; char *argv[20]; int argc = 0; char *cp; int more; if (!sess) return (0); poll=0; /* don't poll during debug_printf */ do { more = 0; FD_ZERO(&read_set); FD_SET(sess->sock,&read_set); tv.tv_sec = 0; tv.tv_usec = 0; if (select(FD_SETSIZE,&read_set,NULL,NULL,&tv)>0) { if (FD_ISSET(sess->sock,&read_set)) { if (recv(sess->sock, debug_line, REMOTE_DEBUG_MAX_LINE,MSG_PEEK)>0) if ((cp=strchr(debug_line,'\n'))!=NULL) if (recv(sess->sock, debug_line, (cp-debug_line+1),0)>0) { debug_line[cp-debug_line]='\0'; /* remove the new line char */ /* * break down string */ cp = debug_line; while (*cp != '\0') { while (*cp == ' ') cp++; if (*cp == '\0') break; argv[argc++] = cp; if (argc>=20) break; while (*cp != '\0' && *cp != ' ') cp++; if (*cp == 0) break; *cp++ = '\0'; } *cp++ = '\0'; /* * what do we want to do */ if (argc == 0 || argv[0][0]=='#' || argv[0][0] == 0) /* ignore comments */ ; else if (caseless_strcmp(argv[0],"PRIORITY")==0) { if (argc>1) { sess->priority = atoi(argv[1]); if (sess->priority>7) sess->priority = 7; debug_printf(sess,"(6) debug priority changed to %d\n", sess->priority); } } else if (sess->cmd_handler) /* callback cmd handler if registered */ { char name[32]; int rc; strncpy(name, argv[0], sizeof(name)); name[sizeof(name)-1] = 0; rc = sess->cmd_handler(argc, argv, sess->cmd_handle); debug_printf(sess,"(6) cmd '%s' returns %d\n", name, rc); } else debug_printf(sess,"(6) unknown command '%s'\n",argv[0]); more = 1; /* try for more input */ } } } } while (more); poll=1; /* return to polling during debug_printf */ return (0); } /* * send stuff to the debug session */ void debug_printf(debug_session *sess, char *format, ...) { va_list list; va_start (list, format); vsprintf(debug_line,format, list); va_end(list); debug_print_line(sess, debug_line); } void debug_vprintf(debug_session *sess, const char *format, va_list list) { vsprintf(debug_line,format, list); debug_print_line(sess, debug_line); } void debug_dvprintf(debug_session *sess, int priority, const char *file, int line, const char *format, va_list list) { int n = 0; if (priority != 0) n += sprintf(debug_line, "(%d)", priority); if (file) n += sprintf(debug_line+n, " %s:%d: ", file, line); vsprintf(debug_line+n, format, list); debug_print_line(sess, debug_line); } void debug_print_line(debug_session *sess, const char *debug_line) { unsigned char priority=7; if (!sess) return; if (poll) debug_poll(sess); if (debug_line[0]=='(') /* get opening bracket */ if (strchr(debug_line,')')!=NULL) /* find closing bracket */ priority=atoi(debug_line+1); if (priority<=sess->priority) { send(sess->sock, sess->info, strlen(sess->info), 0); send(sess->sock, debug_line, strlen(debug_line), 0); if (debug_line[strlen(debug_line)-1]!='\n') send(sess->sock, "\n", 1, 0); } } void remote_debug_register_cmd_handler(debug_session *sess, remote_debug_cmd_handler fn, void *handle) { if (sess) { sess->cmd_handler = fn; sess->cmd_handle = handle; } } /* * Reads environment variable Inet$DebugHost in the form valhalla:1448 to * obtain IP address and port number. Opens a socket to this host and returns * a structure to be used for subsequent debug calls. Debug session should be * closed using the remote_debug_session_close() function */ void remote_debug_open(char *info, debug_session **db_sess) { int rc; int debug_socket=-1; struct sockaddr_in sockaddr; struct hostent *hostent; debug_session *sess=NULL; char host[40]; char varname[100]; char *port; /* malloc to avoid problems in SVC mode */ if (debug_line == NULL) debug_line = malloc(REMOTE_DEBUG_MAX_LINE); memset(&sockaddr, 0, sizeof(sockaddr)); /* * where do we want to connect to */ sprintf (varname, "Inet$DebugHost_%s", info); if (getenv (varname) == NULL) { if (getenv("Inet$DebugHost")==NULL) goto exit_gracefully; strncpy(host,getenv("Inet$DebugHost"),sizeof(host)); } else strncpy(host,getenv(varname),sizeof(host)); host[sizeof(host)-1] = '\0'; /* * find port */ if ((port=strchr(host,':'))==NULL) goto exit_gracefully; *(port++) = 0; /* terminate host name and leave pointer to port */ sockaddr.sin_port = htons(atoi(port)); if (sockaddr.sin_port==0) goto exit_gracefully; /* * allocate a socket */ do { debug_socket = socket(AF_INET, SOCK_STREAM, 0); } while (debug_socket == 0); hostent = gethostbyname(host); if (hostent == NULL) goto exit_gracefully; sockaddr.sin_family = AF_INET; sockaddr.sin_addr.s_addr = *(u_long*)hostent->h_addr; rc = connect(debug_socket, (struct sockaddr *)&sockaddr, sizeof(sockaddr) ); if (rc<0) goto exit_gracefully; /* * allocate a debug session */ if ((sess=malloc(sizeof(debug_session)))==NULL) goto exit_gracefully; sess->sock = debug_socket; if ((sess->info=malloc(strlen(info)+/*2 - No, you need + 3 JBeranek */ 3))==NULL) goto exit_gracefully; strcpy(sess->info, info); strcat(sess->info, ": "); sess->priority = 7; /* * send initial opening message */ debug_printf(sess,"(6) Open Version %s",REMOTE_DEBUG_VERSION); *db_sess = sess; return; exit_gracefully: if (debug_socket >= 0) socketclose(debug_socket); if (sess) { if (sess->info) free(sess->info); free(sess); } *db_sess = NULL; } /* * close previously opened debug session */ void remote_debug_close(debug_session *sess) { if (sess) { debug_printf(sess,"(6) Close"); if (sess->sock >= 0) socketclose(sess->sock); if (sess->info) free(sess->info); free(sess); } if (debug_line) { free(debug_line); debug_line = NULL; } return; } const char *remotedb_version (void) { return REMOTE_DEBUG_VERSION; }