/* 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 1997-1999 Element 14 Ltd */ /* */ /* This material is the confidential trade secret and proprietary */ /* information of Element 14 Ltd. It may not be reproduced, used */ /* sold, or transferred to any third party without the prior written */ /* consent of Element 14 Ltd. 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" static const char REMOTE_DEBUG_VERSION[] = Module_FullVersion; #define REMOTE_DEBUG_MAX_LINE (10*1024) static int remote_debug_poll=1; static char *debug_line = NULL; /* * compare two strings caselessly */ static int remote_debug_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) { static char sbuff[REMOTE_DEBUG_MAX_LINE]; fd_set read_set; struct timeval tv; char *argv[20]; int argc = 0; char *cp; int more; if (!sess) return (0); remote_debug_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)) { int recv_len = recv(sess->sock, sbuff, REMOTE_DEBUG_MAX_LINE-1,MSG_PEEK); if (recv_len>0) { if ((cp=memchr(sbuff,'\n', recv_len))!=NULL) { if (recv(sess->sock, sbuff, (cp-sbuff+1),0)>0) { sbuff[cp-sbuff]='\0'; /* remove the new line char */ /* * break down string */ cp = sbuff; 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 (remote_debug_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 if (remote_debug_caseless_strcmp(argv[0], ":ack")==0) { /* Discard these silently */ } else { debug_printf(sess,"(6) unknown command '%s'\n",argv[0]); } more = 1; /* try for more input */ } } } } } } while (more); remote_debug_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 *line) { remote_debug_print_line (0u, sess, line, strlen (line)); } void remote_debug_print_line (unsigned int flags, debug_session *sess, const char *line, size_t len) { unsigned char priority = 7; if (!sess) return; if (remote_debug_poll) debug_poll(sess); /* Not raw */ if ((flags & 1) == 0) { /* Get opening bracket */ if (line[0]=='(') { /* Find closing bracket */ if (strchr (line,')') != NULL) priority = atoi (line+1); } /* If we're masking this line out, just return */ if (priority > sess->priority) return; /* Send the info string to the socket */ send (sess->sock, sess->info, strlen (sess->info), 0); } /* Send the actual debug data */ send (sess->sock, line, len, 0); /* Not raw */ if ((flags & 1) == 0) { /* And if we're not in raw mode, output a \n if the debug data doesn't end with one */ if (line[len-1] != '\n') send (sess->sock, "\n", strlen ("\n"), 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 == -1); hostent = gethostbyname(host); if (hostent == NULL) goto exit_gracefully; sockaddr.sin_family = AF_INET; #ifndef COMPAT_INET4 sockaddr.sin_len = sizeof(sockaddr); #endif 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; sess->cmd_handler = NULL; sess->cmd_handle = NULL; if ((sess->info=malloc(strlen(info)+sizeof(": ")))==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); debug_socket = -1; 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 *remote_debug_version (void) { return REMOTE_DEBUG_VERSION; }