Commit | Line | Data |
---|---|---|
d44e3c4f | 1 | /****************************************************************************** |
2 | * Copyright (c) 2000-2016 Ericsson Telecom AB | |
3 | * All rights reserved. This program and the accompanying materials | |
4 | * are made available under the terms of the Eclipse Public License v1.0 | |
5 | * which accompanies this distribution, and is available at | |
6 | * http://www.eclipse.org/legal/epl-v10.html | |
7 | * | |
8 | * Contributors: | |
9 | * Balasko, Jeno | |
10 | * Lovassy, Arpad | |
11 | * | |
12 | ******************************************************************************/ | |
970ed795 EL |
13 | #include "jnimw.h" |
14 | #include <stdio.h> | |
15 | #include <stdlib.h> | |
16 | #include <unistd.h> | |
17 | #include <memory.h> | |
18 | #include <string.h> | |
19 | #include <errno.h> | |
20 | ||
21 | #include "../core/Logger.hh" | |
22 | ||
23 | using mctr::MainController; | |
24 | using namespace jnimw; | |
25 | ||
26 | Jnimw *Jnimw::userInterface; | |
27 | bool Jnimw::has_status_message_pending; | |
28 | int Jnimw::pipe_size; | |
29 | ||
30 | /** | |
31 | * The last MC state. It is needed by status_change(), as | |
32 | * status change message is written to the pipe when any status (MC, TC, HC) was changed AND | |
33 | * ( currently there is no status change message on the pipe (signalled by has_status_message_pending) | |
34 | * OR MC state is changed ) | |
35 | */ | |
36 | mctr::mc_state_enum last_mc_state; | |
37 | ||
38 | pthread_mutex_t Jnimw::mutex = PTHREAD_MUTEX_INITIALIZER; | |
39 | ||
40 | /** | |
41 | * Config data, which was created by Java_org_eclipse_titan_executor_jni_JNIMiddleWare_set_1cfg_1file() | |
42 | * by a JNI request, and the result will be used by | |
43 | * Java_org_eclipse_titan_executor_jni_JNIMiddleWare_configure(). | |
44 | * This is done this way to use process_config_read_file() for processing the config file | |
45 | * instead of processing it on the Java side. | |
46 | */ | |
47 | config_data Jnimw::mycfg; | |
48 | ||
49 | void Jnimw::lock() | |
50 | { | |
51 | int result = pthread_mutex_lock(&mutex); | |
52 | if (result > 0) { | |
53 | fatal_error("Jni middleware::lock: " | |
54 | "pthread_mutex_lock failed with code %d.", result); | |
55 | } | |
56 | } | |
57 | ||
58 | void Jnimw::unlock() | |
59 | { | |
60 | int result = pthread_mutex_unlock(&mutex); | |
61 | if (result > 0) { | |
62 | fatal_error("Jni middleware:::unlock: " | |
63 | "pthread_mutex_unlock failed with code %d.", result); | |
64 | } | |
65 | } | |
66 | ||
67 | void Jnimw::fatal_error(const char *fmt, ...) | |
68 | { | |
69 | va_list ap; | |
70 | va_start(ap, fmt); | |
71 | vfprintf(stderr, fmt, ap); | |
72 | va_end(ap); | |
73 | if (errno != 0) fprintf(stderr, " (%s)", strerror(errno)); | |
74 | putc('\n', stderr); | |
75 | exit(EXIT_FAILURE); | |
76 | } | |
77 | ||
78 | int Jnimw::enterLoop(int, char*[]) { | |
79 | return EXIT_SUCCESS; | |
80 | } | |
81 | ||
82 | Jnimw::Jnimw() | |
83 | { | |
84 | pipe_buffer = NULL; | |
85 | pipe_fd[0] = -1; | |
86 | pipe_fd[1] = -1; | |
87 | ||
88 | create_pipe(); | |
89 | FD_ZERO(&readfds); | |
90 | FD_SET(pipe_fd[0], &readfds); | |
91 | ||
92 | has_status_message_pending = false; | |
93 | last_mc_state = mctr::MC_INACTIVE; | |
94 | pipe_size = 0; | |
95 | ||
96 | if (pthread_mutex_init(&mutex, NULL)) | |
97 | fatal_error("Jni middleware::constructor: pthread_mutex_init failed."); | |
98 | ||
99 | } | |
100 | ||
101 | Jnimw::~Jnimw() | |
102 | { | |
103 | destroy_pipe(); | |
104 | pthread_mutex_destroy(&mutex); | |
105 | } | |
106 | ||
107 | ||
108 | void strreverse(char* begin, char* end) { | |
109 | char aux; | |
110 | while(end>begin){ | |
111 | aux=*end, *end--=*begin, *begin++=aux; | |
112 | } | |
113 | } | |
114 | ||
115 | /** | |
116 | * Ansi C "itoa" based on Kernighan & Ritchie's "Ansi C": | |
117 | */ | |
118 | void itoa(int value, char* str) { | |
119 | static char num[] = "0123456789"; | |
120 | char* wstr=str; | |
121 | ||
122 | // Conversion. Number is reversed. | |
123 | do *wstr++ = num[value%10]; while(value/=10); | |
124 | *wstr='\0'; | |
125 | ||
126 | // Reverse string | |
127 | strreverse(str,wstr-1); | |
128 | } | |
129 | ||
130 | void create_packet_header(const int source_length, char* dest, char method_id) { | |
131 | char packet_size[6]; | |
132 | dest[0] = method_id; | |
133 | itoa(source_length, packet_size); | |
134 | int i; | |
135 | for(i = 1; i < 6; i++) dest[i] = '0'; | |
136 | dest[6] = '\0'; | |
137 | int j = strlen(packet_size); | |
138 | for(i = 0; i < j; i++) dest[5-i] = packet_size[j-i-1]; | |
139 | } | |
140 | ||
141 | char* stuffer(const char* msg){ | |
142 | char* msg_stuffed = (char*) malloc(strlen(msg)*2); | |
143 | int i = 0; | |
144 | int j = 0; | |
145 | while(msg[i] != '\0') { | |
146 | if(msg[i] != '|' && msg[i] != '\\') { | |
147 | msg_stuffed[j++] = msg[i]; | |
148 | } else { | |
149 | msg_stuffed[j++] = '\\'; | |
150 | msg_stuffed[j++] = msg[i]; | |
151 | } | |
152 | i++; | |
153 | } | |
154 | msg_stuffed[j] = '\0'; | |
155 | ||
156 | return msg_stuffed; | |
157 | } | |
158 | ||
159 | //---------------------------------------------------------------------------- | |
160 | // USERINTERFACE | |
161 | ||
162 | void Jnimw::status_change() | |
163 | { | |
164 | lock(); | |
165 | mctr::mc_state_enum mc_state = MainController::get_state(); | |
166 | if(last_mc_state != mc_state || !has_status_message_pending){ | |
167 | char str[7]; | |
168 | sprintf( str,"S%02d000", mc_state ); | |
169 | write_pipe( str ); | |
170 | } | |
171 | has_status_message_pending = true; | |
172 | last_mc_state = mc_state; | |
173 | unlock(); | |
174 | } | |
175 | ||
176 | //---------------------------------------------------------------------------- | |
177 | // USERINTERFACE | |
178 | ||
179 | void Jnimw::error(int severity, const char* msg) | |
180 | { | |
181 | char *msg_stuffed = stuffer(msg); | |
182 | expstring_t pipe_s; | |
183 | ||
184 | // creating packet header | |
185 | char packet_header[7]; | |
186 | expstring_t tmp; | |
187 | tmp = mprintf("%d|%s", severity, msg_stuffed); | |
188 | create_packet_header(strlen(tmp), packet_header, 'E'); | |
189 | ||
190 | pipe_s = mprintf("%s%s", packet_header, tmp); | |
191 | free(msg_stuffed); | |
192 | ||
193 | write_pipe(pipe_s); | |
194 | } | |
195 | ||
196 | //---------------------------------------------------------------------------- | |
197 | // USERINTERFACE | |
198 | ||
199 | void Jnimw::notify(const struct timeval* time, const char* source, | |
200 | int severity, const char* msg) | |
201 | { | |
202 | char *source_stuffed = stuffer(source); | |
203 | char *msg_stuffed = stuffer(msg); | |
204 | expstring_t pipe_s; | |
205 | ||
206 | // creating packet header | |
207 | char packet_header[7]; | |
208 | expstring_t tmp; | |
209 | tmp = mprintf("%ld|%ld|%s|%d|%s", time->tv_sec, time->tv_usec, source_stuffed, severity, msg_stuffed); | |
210 | create_packet_header(strlen(tmp), packet_header, 'N'); | |
211 | ||
212 | pipe_s = mprintf("%s%s", packet_header, tmp); | |
213 | write_pipe(pipe_s); | |
214 | free(source_stuffed); | |
215 | free(msg_stuffed); | |
216 | Free(tmp); | |
217 | Free(pipe_s); | |
218 | } | |
219 | ||
220 | void Jnimw::create_pipe() | |
221 | { | |
222 | if (pipe(pipe_fd)){ | |
223 | printf("Jnimw::create_pipes(): pipe system call failed.\n"); | |
224 | } | |
225 | } | |
226 | ||
227 | void Jnimw::destroy_pipe() | |
228 | { | |
229 | close(pipe_fd[0]); | |
230 | pipe_fd[0] = -1; | |
231 | close(pipe_fd[1]); | |
232 | pipe_fd[1] = -1; | |
233 | } | |
234 | ||
235 | bool Jnimw::is_pipe_readable(){ | |
236 | // TODO maybe this could get faster | |
237 | timeval time; | |
238 | time.tv_sec = 0; | |
239 | time.tv_usec = 0; | |
240 | fd_set read_set; | |
241 | FD_ZERO(&read_set); | |
242 | FD_SET(pipe_fd[0], &read_set); | |
243 | int ret = select(pipe_fd[0] + 1 , &read_set, NULL, NULL, &time); | |
244 | return ret > 0; | |
245 | } | |
246 | ||
247 | char* Jnimw::read_pipe() | |
248 | { | |
249 | select(pipe_fd[0] + 1 , &readfds, NULL, NULL, NULL); | |
250 | lock(); | |
251 | ||
252 | pipe_buffer = (char*)malloc(7); | |
253 | int ret = read(pipe_fd[0], pipe_buffer, 6); | |
254 | if(ret != 6){ | |
255 | printf("Malformed packet arrived!\n"); | |
256 | } | |
257 | ||
258 | pipe_size-= ret; | |
259 | ||
260 | if(pipe_buffer[0] == 'S'){ | |
261 | has_status_message_pending = false; | |
262 | ||
263 | unlock(); | |
264 | return pipe_buffer; | |
265 | } | |
266 | ||
267 | int packet_size = (pipe_buffer[1]-48) * 10000 + (pipe_buffer[2]-48) * 1000 + | |
268 | (pipe_buffer[3]-48) * 100 + (pipe_buffer[4]-48) * 10 + (pipe_buffer[5]-48); | |
269 | ||
270 | pipe_buffer = (char*)realloc(pipe_buffer, packet_size + 7); | |
271 | ||
272 | ret = read(pipe_fd[0],pipe_buffer + 6, packet_size); | |
273 | if(ret != packet_size){ | |
274 | printf("Jnimw::read_pipe(): read system call failed\n"); | |
275 | } | |
276 | pipe_buffer[packet_size + 6] = '\0'; | |
277 | ||
278 | pipe_size-=ret; | |
279 | ||
280 | unlock(); | |
281 | return pipe_buffer; | |
282 | } | |
283 | ||
284 | void Jnimw::write_pipe(const char *buf) | |
285 | { | |
286 | if (write(pipe_fd[1], buf, strlen(buf)) < 0){ | |
287 | printf("Jnimw::write_pipe(): write system call failed\n"); | |
288 | } | |
289 | ||
290 | pipe_size+=strlen(buf); | |
291 | } |