/* * "Software pw3270, desenvolvido com base nos códigos fontes do WC3270 e X3270 * (Paul Mattes Paul.Mattes@usa.net), de emulação de terminal 3270 para acesso a * aplicativos mainframe. Registro no INPI sob o nome G3270. * * Copyright (C) <2008> * * Este programa é software livre. Você pode redistribuí-lo e/ou modificá-lo sob * os termos da GPL v.2 - Licença Pública Geral GNU, conforme publicado pela * Free Software Foundation. * * Este programa é distribuído na expectativa de ser útil, mas SEM QUALQUER * GARANTIA; sem mesmo a garantia implícita de COMERCIALIZAÇÃO ou de ADEQUAÇÃO * A QUALQUER PROPÓSITO EM PARTICULAR. Consulte a Licença Pública Geral GNU para * obter mais detalhes. * * Você deve ter recebido uma cópia da Licença Pública Geral GNU junto com este * programa; se não, escreva para a Free Software Foundation, Inc., 59 Temple * Place, Suite 330, Boston, MA, 02111-1307, USA * * Este programa está nomeado como pipesource.c e possui - linhas de código. * * Contatos: * * perry.werneck@gmail.com (Alexandre Perry de Souza Werneck) * erico.mendonca@gmail.com (Erico Mascarenhas Mendonça) * licinio@bb.com.br (Licínio Luis Branco) * kraucer@bb.com.br (Kraucer Fernandes Mazuco) * */ #include #include #include #include #include "remotectl.h" /*---[ Defines ]----------------------------------------------------------------------------*/ #pragma pack(1) typedef struct _pipe_source { GSource gsrc; HANDLE hPipe; enum _PIPE_STATE { PIPE_STATE_WAITING, PIPE_STATE_READ, PIPE_STATE_PENDING_READ, PIPE_STATE_UNDEFINED, } state; OVERLAPPED overlap; unsigned char buffer[PIPE_BUFFER_LENGTH+1]; } pipe_source; #pragma pack() /*---[ GSource ]----------------------------------------------------------------------------*/ static void wait_for_client(pipe_source *source) { set_active(FALSE); if(ConnectNamedPipe(source->hPipe,&source->overlap)) { popup_lasterror("%s",_( "Error in ConnectNamedPipe" )); return; } switch(GetLastError()) { // The overlapped connection in progress. case ERROR_IO_PENDING: // trace("%s: ERROR_IO_PENDING",__FUNCTION__); source->state = PIPE_STATE_WAITING; break; // Client is already connected, so signal an event. case ERROR_PIPE_CONNECTED: trace("%s: ERROR_PIPE_CONNECTED",__FUNCTION__); set_active(TRUE); if(SetEvent(source->overlap.hEvent)) break; // If an error occurs during the connect operation... default: popup_lasterror("%s", _( "ConnectNamedPipe failed" )); } } static gboolean IO_prepare(GSource *source, gint *timeout) { /* * Called before all the file descriptors are polled. * If the source can determine that it is ready here * (without waiting for the results of the poll() call) * it should return TRUE. * * It can also return a timeout_ value which should be the maximum * timeout (in milliseconds) which should be passed to the poll() call. * The actual timeout used will be -1 if all sources returned -1, * or it will be the minimum of all the timeout_ values * returned which were >= 0. * */ if(WaitForSingleObject(((pipe_source *) source)->overlap.hEvent,0) == WAIT_OBJECT_0) { // trace("%s: source=%p",__FUNCTION__,source); return TRUE; } *timeout = 10; return FALSE; } static gboolean IO_check(GSource *source) { /* * Called after all the file descriptors are polled. * The source should return TRUE if it is ready to be dispatched. * Note that some time may have passed since the previous prepare * function was called, so the source should be checked again here. * */ if(WaitForSingleObject(((pipe_source *) source)->overlap.hEvent,0) == WAIT_OBJECT_0) return TRUE; return FALSE; } static void process_input(pipe_source *source, DWORD cbRead) { HLLAPI_DATA * data = (HLLAPI_DATA *) source->buffer; QUERY * qry = g_malloc0(sizeof(QUERY)+cbRead+1); qry->hPipe = source->hPipe; qry->text = (const gchar *) (qry+1); if(data->id == HLLAPI_REQUEST_QUERY) { // HLLAPI query qry->cmd = (int) data->func; qry->pos = (int) data->rc; qry->length = data->value; memcpy((gchar *)(qry->text),data->string,qry->length); } else { qry->cmd = -1; } enqueue_request(qry); } void request_complete(QUERY *qry, int rc, const gchar *text) { request_buffer(qry,rc,strlen(text),(const gpointer) text); } void request_status(QUERY *qry, int rc) { if(rc) { const gchar *msg = strerror(rc); request_buffer(qry, rc, strlen(msg), (const gpointer) msg); } else { request_buffer(qry, rc, 0, NULL); } } void request_value(QUERY *qry, int rc, unsigned int value) { HLLAPI_DATA data; memset(&data,0,sizeof(data)); data.id = HLLAPI_RESPONSE_VALUE; data.func = qry->cmd; data.rc = rc; data.value = value; #ifdef WIN32 { DWORD wrote = sizeof(data); WriteFile(qry->hPipe,&data,wrote,&wrote,NULL); trace("Wrote=%d len=%d",(int) wrote, sizeof(data)); } #endif // WIN32 g_free(qry); } void request_buffer(QUERY *qry, int rc, size_t szBuffer, const gpointer buffer) { size_t sz; HLLAPI_DATA *data; if(buffer) { sz = sizeof(HLLAPI_DATA)+szBuffer; data = g_malloc0(sz); data->id = HLLAPI_RESPONSE_TEXT; memcpy(data->string,buffer,szBuffer); } else { sz = sizeof(HLLAPI_DATA); data = g_malloc0(sz); data->id = HLLAPI_RESPONSE_VALUE; } data->func = qry->cmd; data->rc = rc; data->value = szBuffer; trace("rc=%d data->len=%d",rc,(int) szBuffer); #ifdef WIN32 { DWORD wrote = sz; WriteFile(qry->hPipe,data,wrote,&wrote,NULL); trace("Wrote=%d len=%d",(int) wrote, (int) sz); } #endif // WIN32 g_free(data); g_free(qry); } static void read_input_pipe(pipe_source *source) { DWORD cbRead = 0; if(ReadFile(source->hPipe,source->buffer,PIPE_BUFFER_LENGTH,&cbRead,&source->overlap) && cbRead > 0) process_input(source,cbRead); // The read operation is still pending. switch(GetLastError()) { case 0: break; case ERROR_IO_PENDING: // trace("%s: PIPE_STATE_PENDING_READ",__FUNCTION__); source->state = PIPE_STATE_PENDING_READ; break; case ERROR_PIPE_LISTENING: // trace("%s: ERROR_PIPE_LISTENING",__FUNCTION__); source->state = PIPE_STATE_READ; break; case ERROR_BROKEN_PIPE: trace("%s: ERROR_BROKEN_PIPE",__FUNCTION__); if(!DisconnectNamedPipe(source->hPipe)) { set_active(FALSE); popup_lasterror("%s",_( "Error in DisconnectNamedPipe" )); } else { wait_for_client(source); } break; case ERROR_PIPE_NOT_CONNECTED: trace("%s: ERROR_PIPE_NOT_CONNECTED",__FUNCTION__); set_active(FALSE); break; default: if(source->hPipe != INVALID_HANDLE_VALUE) popup_lasterror("%s",_( "Error receiving message from pipe" ) ); } } static gboolean IO_dispatch(GSource *source, GSourceFunc callback, gpointer data) { /* * Called to dispatch the event source, * after it has returned TRUE in either its prepare or its check function. * The dispatch function is passed in a callback function and data. * The callback function may be NULL if the source was never connected * to a callback using g_source_set_callback(). The dispatch function * should call the callback function with user_data and whatever additional * parameters are needed for this type of event source. */ BOOL fSuccess; DWORD cbRead = 0; // DWORD dwErr = 0; fSuccess = GetOverlappedResult(((pipe_source *) source)->hPipe,&((pipe_source *) source)->overlap,&cbRead,FALSE ); // trace("%s: source=%p data=%p Result=%s cbRead=%d",__FUNCTION__,source,data,fSuccess ? "Success" : "Unsuccess",(int) cbRead); switch(((pipe_source *) source)->state) { case PIPE_STATE_WAITING: if(fSuccess) { trace("Pipe connected (cbRet=%d)",(int) cbRead); set_active(TRUE); ((pipe_source *) source)->state = PIPE_STATE_READ; } else { popup_lasterror("%s", _( "Pipe connection failed" )); } break; case PIPE_STATE_READ: // trace("Reading pipe (cbRead=%d)",(int) cbRead); read_input_pipe( (pipe_source *) source); break; case PIPE_STATE_PENDING_READ: if(fSuccess && cbRead > 0) process_input((pipe_source *) source,cbRead); ((pipe_source *) source)->state = PIPE_STATE_READ; break; //#ifdef DEBUG // default: // trace("%s: source=%p data=%p Unexpected mode %d",__FUNCTION__,source,data,((pipe_source *) source)->state); //#endif } return TRUE; } static void IO_finalize(GSource *source) { // trace("%s: source=%p",__FUNCTION__,source); if( ((pipe_source *) source)->hPipe != INVALID_HANDLE_VALUE) { CloseHandle(((pipe_source *) source)->hPipe); ((pipe_source *) source)->hPipe = INVALID_HANDLE_VALUE; } } static gboolean IO_closure(gpointer data) { // trace("%s: data=%p",__FUNCTION__,data); return 0; } void init_source_pipe(HANDLE hPipe) { static GSourceFuncs pipe_source_funcs = { IO_prepare, IO_check, IO_dispatch, IO_finalize, IO_closure, NULL }; pipe_source *source = (pipe_source *) g_source_new(&pipe_source_funcs,sizeof(pipe_source)); source->hPipe = hPipe; source->state = PIPE_STATE_WAITING; source->overlap.hEvent = CreateEvent( NULL,TRUE,TRUE,NULL); g_source_attach((GSource *) source,NULL); wait_for_client(source); return; }