Work on van PC
[UnoTest.git] / TCPClient.cpp
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <netdb.h>
6 #include <pthread.h>
7 #include <unistd.h>
8 #include <termios.h>
9 #include <arpa/inet.h>
10 #include <signal.h>
11
12 #define MAX_STRING 256
13
14 #define SOCKETTYPE SOCK_STREAM
15 #define SOCKETPROTOCOL IPPROTO_TCP
16
17 #define PARAMETERCOUNT 2
18
19 static struct sockaddr_in Socket;
20 static socklen_t SocketSize = sizeof (Socket);
21 static int SocketHandle;
22 static struct sockaddr_in RemoteSocket;
23 static socklen_t RemoteSocketSize = sizeof (RemoteSocket);
24 static int RemoteSocketHandle;
25 static struct termios PreviousConfiguration;
26 static pthread_t ListenerThreadHandle;
27
28 static volatile bool Run = true;
29
30 void *ListenerThread (void *)
31 {
32     char TextBuffer[MAX_STRING];
33     ssize_t BytesRead;
34
35     while (Run)
36     {
37         if ((BytesRead = read (RemoteSocketHandle, TextBuffer, MAX_STRING)) > 0)
38         {
39             *(TextBuffer + BytesRead) = '\0';
40
41             fputs (TextBuffer, stdout);
42         }
43     }
44 }
45
46 void init ()
47 {
48     struct termios Configuration;
49
50     fflush (stdout);
51
52     if (tcgetattr (STDIN_FILENO, &PreviousConfiguration) < 0)
53         perror ("tcgetattr()");
54
55     PreviousConfiguration.c_lflag &= ICANON;    // Enable canonical mode (default).
56     PreviousConfiguration.c_lflag &= ECHO;  // Echo input characters.
57
58     if (tcgetattr (STDIN_FILENO, &Configuration) < 0)
59         perror ("tcgetattr()");
60
61     Configuration.c_lflag &= ~ICANON;   // (en|dis)able canonical mode (default)
62     Configuration.c_lflag &= ~ECHO; // Echo input characters.
63     Configuration.c_cc[VMIN] = 1;   // Minimum number of characters.
64     Configuration.c_cc[VTIME] = 0;  // Timeout in deciseconds
65
66     if (tcsetattr (STDIN_FILENO, TCSAFLUSH, &Configuration) < 0)
67         perror ("tcsetattr TCSANOW");
68 }
69
70 void reset ()
71 {
72     fflush (stdout);
73
74     if (tcsetattr (STDIN_FILENO, TCSANOW, &PreviousConfiguration) < 0)
75         perror ("tcsetattr TCSANOW");
76 }
77
78 int main (int argc, char *argv[])
79 {
80     printf ("Graham's immediate TCP client, " __DATE__ " (" __TIME__ ")\n");
81
82     if (argc <= PARAMETERCOUNT)
83     {
84         printf ("USE: program <server ip> <port>\n");
85         exit (0);
86     }
87
88     atexit (reset);
89
90     if ((SocketHandle = socket (AF_INET, SOCKETTYPE, SOCKETPROTOCOL)) == -1)
91     {
92         perror ("creating a socket");
93
94         exit (0);
95     }
96
97     Socket.sin_family = AF_INET;
98     Socket.sin_port = htons (atoi (argv[2]));
99
100     if (inet_aton (argv[1], &Socket.sin_addr) == 0)
101     {
102         fprintf (stderr, "inet_aton() failed\n");
103         return 1;
104     }
105
106     // Make socket
107     RemoteSocketHandle = socket (AF_INET, SOCKETTYPE, SOCKETPROTOCOL);
108
109     printf ("Connecting to %s port %u\n", argv[1], atoi (argv[2]));
110
111     // Make connection
112     if ((connect (RemoteSocketHandle, (struct sockaddr *) &Socket, (socklen_t) SocketSize)) == -1)
113     {
114         perror ("Failed\n");
115         return 1;
116     }
117
118     // Spawn the listen/receive deamons
119     pthread_create (&ListenerThreadHandle, NULL, &ListenerThread, NULL);
120
121     init ();
122
123     for (;;)
124     {
125         char KeyPressed = getchar ();
126
127         if (KeyPressed == 27)   // Escape to exit
128         {
129             puts ("Exiting");
130             Run = false;
131             break;
132         }
133
134         if (KeyPressed >= 32 && KeyPressed <= 126)  // Printable only
135             write (RemoteSocketHandle, &KeyPressed, 1);
136     }
137
138     pthread_cancel (ListenerThreadHandle);
139
140     timespec Wait = { 1, 0 };
141
142     // Keep alive until finish condition is done
143     pthread_timedjoin_np (ListenerThreadHandle, NULL, &Wait);
144
145     close (RemoteSocketHandle);
146     close (SocketHandle);
147
148     reset ();
149
150     puts ("Bye");
151
152     exit (0);
153
154     return 0;
155 }