#include #include #include #include #include #include #include #include #include "response.h" #include "version.h" static int port = 3333; #define BUFSIZE 1024 GMainContext *context=NULL; GMainLoop *mainLoop=NULL; GSocketConnection * connection = NULL; GSocketClient * client = NULL; char exitTokens[5][7] = {"quit", "exit", "logout", "logoff", "local"}; //helper function to nicely terminate the client static void terminate(char *message, int exitCode) { g_object_unref(client); g_object_unref(connection); if (message) { g_print("%s\n", message); } exit(exitCode); } //a sort of strncmp but with \n or \r exception static gboolean Matches(char *src, char* dst, gssize size) { for(; *src != '\0', (size--)>0; src++) { if(g_ascii_toupper(*src) != g_ascii_toupper(*dst)) { return FALSE; } dst++; } for(; *dst != '\0'; dst++) if (*dst != '\r' && *dst != '\n') { return FALSE; } return TRUE; } #define TIMEOUT 100000 // 100000 useconds, 100ms #define ONESECONDINUSEC 1000000 //GIOChannel callback static gboolean stdinAvailable (GIOChannel *source, GIOCondition condition, gpointer data) { char tmp[BUFSIZE]; memset(tmp,0,BUFSIZE); int size = read(0, tmp, BUFSIZE); if(size<=0) { return TRUE; } // Ignore second \n if two are sent in rapid succession. // This happens when the serial input is terminated with \r\n, // which getty translates to \n\n. The IO handler splits this // into 2 input lines, so we can't use a simple regex to // replace it. static struct timeval last = { 0, 0 }; // the time this last ran static struct timeval now; // the time now gettimeofday(&now, NULL ); if (last.tv_sec != 0) { // shouldn't be zero if we have been in here before if (strcmp(tmp, "\n") == 0) { // is this a newline all on it's own? if (last.tv_sec == now.tv_sec) { // if we're in the same second we can just check the usec field if (now.tv_usec - last.tv_usec < TIMEOUT) { // ignore this \n return TRUE; } } // - check that last and now sec fields are only one second apart // - check that the time elapsed in this second is smaller than the // timeout, if it isn't we don't need to check the other second // - check that there is less of the last second remaining than the timeout else if (now.tv_sec - last.tv_sec == 1 && now.tv_usec < TIMEOUT && (ONESECONDINUSEC - last.tv_usec) < TIMEOUT) { // and then check the the time left in the last second // plus the time in this second is less than the timeout if ((ONESECONDINUSEC - last.tv_usec) + now.tv_usec < TIMEOUT) { // ignore this \n return TRUE; } } } } last = now; //test if we have an exit word int idx=0; for(idx=0; idxmessage) { g_print("Got error: %s\n", error->message); } if (written != size || written <= 0) { g_print("Could not write. blocking. Written: %d\n", written); return FALSE; } return TRUE; } //callback for server input static gboolean cbServerInput(gpointer data, gpointer additional) { char buffer[BUFSIZE]; gssize size=0; memset(buffer,0,BUFSIZE); GPollableInputStream* inStream = (GPollableInputStream*)data; GError *error = NULL; size=g_pollable_input_stream_read_nonblocking(inStream, buffer, BUFSIZE, NULL, &error); if(size <=0) { terminate("Connection to server lost", -1); } if(buffer[0] != ' ') { g_print("%s", buffer); } return TRUE; } int main(int argc, char** argv) { /* create a new connection */ g_type_init (); GOutputStream *out; GInputStream *in; GError* error = NULL; GIOChannel* stdinChannel = NULL; client = g_socket_client_new(); /* connect to the host */ connection = g_socket_client_connect_to_host (client, (gchar*)"localhost", port, NULL, &error); if (error != NULL) { g_print("Could not connect to server on port %d\n", port); g_object_unref(client); return -1; } g_printf("\nWelcome to InstrumentShell v%s\n\n",FW_VERSION); g_print("> "); //register Pollable sources out = g_io_stream_get_output_stream (G_IO_STREAM (connection)); in = g_io_stream_get_input_stream (G_IO_STREAM (connection)); GSource *outSource = NULL; GSource *inSource = g_pollable_input_stream_create_source((struct GPollableInputStream*)in, NULL); outSource = g_pollable_output_stream_create_source((struct GPollableOutputStream*)out, NULL); //register stdin channel stdinChannel = g_io_channel_unix_new(0); if(stdinChannel == NULL) { terminate("Could not open STDIN channel", -2); } //attach the sources g_io_add_watch(stdinChannel, G_IO_IN, stdinAvailable, (struct GPollableOutputStream*)out); g_source_set_callback(inSource, cbServerInput, (GPollableOutputStream*)in, NULL); g_source_attach(inSource, NULL); g_main_loop_run (g_main_loop_new (NULL, FALSE)); return 0; }