static
void
globus_l_gram_streamer_data_callback(
    void *                              arg,
    globus_gass_transfer_request_t      request,
    globus_byte_t *                     bytes,
    globus_size_t                       length,
    globus_bool_t                       last_data)
{
    globus_gram_streamer_monitor_t *    monitor = arg;
    globus_gram_stream_t *              stream;
    globus_gass_transfer_request_status_t
                                        status;

    globus_mutex_lock(&monitor->mutex);
    stream = globus_gass_transfer_request_get_user_pointer(request);
    free(bytes);
    stream->blocks--;
    status = globus_gass_transfer_request_get_status(request);

    if (last_data && stream->blocks == 0)
    {
        switch (status)
        {
        case GLOBUS_GASS_TRANSFER_REQUEST_INVALID:
        case GLOBUS_GASS_TRANSFER_REQUEST_STARTING:
        case GLOBUS_GASS_TRANSFER_REQUEST_FAILED:
        case GLOBUS_GASS_TRANSFER_REQUEST_DENIED:
        case GLOBUS_GASS_TRANSFER_REQUEST_REFERRED:
            globus_gass_transfer_request_destroy(request);
            if (stream->state != GLOBUS_GRAM_STREAM_RESTART)
            {
                stream->state = GLOBUS_GRAM_STREAM_FAIL;
                globus_cond_signal(&monitor->cond);
            }
            break;
        case GLOBUS_GASS_TRANSFER_REQUEST_DONE:
            globus_gass_transfer_request_destroy(request);
            if (stream->state == GLOBUS_GRAM_STREAM_ACTIVE)
            {
                stream->state = GLOBUS_GRAM_STREAM_DONE;
            }
            globus_cond_signal(&monitor->cond);
            break;
        case GLOBUS_GASS_TRANSFER_REQUEST_PENDING:
            break;
        default:
            fprintf(stderr, "%d:GASS Transfer returned invalid status: %d\n",
                    GLOBUS_GRAM_PROTOCOL_ERROR_MALLOC_FAILED,
                    (int) status);
            exit(EXIT_FAILURE);
        }
    }
    globus_mutex_unlock(&monitor->mutex);
}
static
void
globus_l_gram_streamer_request_ready(
    void *                              arg,
    globus_gass_transfer_request_t      request)
{
    globus_gram_streamer_monitor_t *    monitor = arg;
    globus_gram_stream_t *              stream;
    globus_gass_transfer_request_status_t
                                        status;
    globus_mutex_lock(&monitor->mutex);
    stream = globus_gass_transfer_request_get_user_pointer(request);
    status = globus_gass_transfer_request_get_status(request);

    switch (status)
    {
    case GLOBUS_GASS_TRANSFER_REQUEST_INVALID:
    case GLOBUS_GASS_TRANSFER_REQUEST_STARTING:
        globus_gass_transfer_request_destroy(request);
        stream->state = GLOBUS_GRAM_STREAM_FAIL;
        globus_cond_signal(&monitor->cond);
        break;
    case GLOBUS_GASS_TRANSFER_REQUEST_FAILED:
    case GLOBUS_GASS_TRANSFER_REQUEST_DENIED:
        globus_gass_transfer_request_destroy(request);
        stream->state = GLOBUS_GRAM_STREAM_FAIL;
        globus_cond_signal(&monitor->cond);
        break;
    case GLOBUS_GASS_TRANSFER_REQUEST_REFERRED:
        globus_gass_transfer_request_destroy(request);
        stream->state = GLOBUS_GRAM_STREAM_DONE;
        globus_cond_signal(&monitor->cond);
        break;
    case GLOBUS_GASS_TRANSFER_REQUEST_DONE:
        globus_gass_transfer_request_destroy(request);
        stream->state = GLOBUS_GRAM_STREAM_DONE;
        globus_cond_signal(&monitor->cond);
        break;
    case GLOBUS_GASS_TRANSFER_REQUEST_PENDING:
        stream->state = GLOBUS_GRAM_STREAM_ACTIVE;
        break;
    default:
        fprintf(stderr, "%d:GASS Transfer returned invalid status: %d\n",
                GLOBUS_GRAM_PROTOCOL_ERROR_MALLOC_FAILED,
                (int) status);
        exit(EXIT_FAILURE);
    }
    globus_mutex_unlock(&monitor->mutex);
}
/******************************************************************************
Function: globus_l_gass_server_ez_put_callback()

Description: 

Parameters: 

Returns: 
******************************************************************************/
static void
globus_l_gass_server_ez_put_callback(
				    void *arg,
				    globus_gass_transfer_request_t request,
				    globus_byte_t *     bytes,
				    globus_size_t       len,
				    globus_bool_t       last_data)
{
    int fd;

    fd = (int) arg;

    globus_libc_write(fd, bytes, len);
    if(!last_data)
    {
        globus_gass_transfer_receive_bytes(request,
                                           bytes,
                                           1024,
                                           1,
                                           globus_l_gass_server_ez_put_callback,
                                           arg);
    return ;
    }

    if((fd!=fileno(stdout)) && (fd!=fileno(stderr)))
    {
        close(fd);
    }
    globus_free(bytes);
    globus_gass_transfer_request_destroy(request);
    return ;

} /* globus_l_gass_server_ez_put_callback() */
static
void
test_l_data_callback(
    void *                              arg,
    globus_gass_transfer_request_t      request,
    globus_byte_t *                     bytes,
    globus_size_t                       length,
    globus_bool_t                       last_data)
{
    test_monitor_t                      *monitor = arg;

    if (last_data)
    {
        globus_gass_transfer_request_destroy(request);
        return;
    }

    globus_gass_transfer_receive_bytes(
        request,
        bytes,
        sizeof(monitor->old_output),
        1,
        test_l_data_callback,
        monitor);
}
/******************************************************************************
Function: globus_l_gass_server_ez_get_callback()

Description: 

Parameters: 

Returns: 
******************************************************************************/
static void 
globus_l_gass_server_ez_get_callback(
    void *arg,
    globus_gass_transfer_request_t request,
    globus_byte_t *     bytes,
    globus_size_t       len,
    globus_bool_t       last_data)
{
    int fd;
    globus_size_t amt;

    fd=(int) arg;
    if(!last_data)
    {
	amt = globus_libc_read(fd, bytes, len);
        if(amt == 0)
        {
            globus_gass_transfer_send_bytes(request,
                                            bytes,
                                            0,
                                            GLOBUS_TRUE,
                                            globus_l_gass_server_ez_get_callback,
                                            arg);
        }
        else
        {
            globus_gass_transfer_send_bytes(request,
                                            bytes,
                                            amt,
                                            GLOBUS_FALSE,
                                            globus_l_gass_server_ez_get_callback,
                                            arg);
        }
        return;
    }

    if((fd!=fileno(stdout))&&(fd!=fileno(stderr)))
    {
        close(fd);
    }
    globus_free(bytes);
    globus_gass_transfer_request_destroy(request);

} /* globus_l_gass_server_ez_get_callback() */
static void
globus_l_gass_server_ez_register_accept_callback(
					void * listener,
					globus_gass_transfer_request_t request 
					)
{
    int rc;
    char * subjectname;
    char * path=GLOBUS_NULL;
    char * url;
    globus_url_t parsed_url;
    globus_l_gass_server_ez_t * s;
    globus_gass_server_ez_request_t *r;
    struct stat	statstruct;
    globus_byte_t * buf;
    int amt;
    int flags=0;

    
    subjectname=globus_gass_transfer_request_get_subject(request);

    /* lookup our options */
    s=(globus_l_gass_server_ez_t *)globus_hashtable_lookup(
                                &globus_l_gass_server_ez_listeners,
                                listener);

    /* Check for valid URL */
    url=globus_gass_transfer_request_get_url(request);
    rc = globus_url_parse(url, &parsed_url);
    if(rc != GLOBUS_SUCCESS ||
       parsed_url.url_path == GLOBUS_NULL || strlen(parsed_url.url_path) == 0U)
    {
        globus_gass_transfer_deny(request, 404, "File Not Found");
        globus_gass_transfer_request_destroy(request);
        if (rc == GLOBUS_SUCCESS)
            globus_url_destroy(&parsed_url);
	goto reregister_nourl;
    }

    if(globus_gass_transfer_request_get_type(request) ==
       GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND)
    {
        flags = O_CREAT | O_WRONLY | O_APPEND;
    }
    else if(globus_gass_transfer_request_get_type(request) ==
            GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT)
    {
        flags = O_CREAT | O_WRONLY | O_TRUNC;
    }
    switch(globus_gass_transfer_request_get_type(request))
        {
          case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_APPEND:
          case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_PUT:

	    /* Check to see if this is a request we are allowed to handle */

            if(((s->options & GLOBUS_GASS_SERVER_EZ_WRITE_ENABLE) == 0UL) &&
              ((s->options & GLOBUS_GASS_SERVER_EZ_STDOUT_ENABLE) == 0UL) &&
              ((s->options & GLOBUS_GASS_SERVER_EZ_STDERR_ENABLE) == 0UL) &&
              ((s->options & GLOBUS_GASS_SERVER_EZ_CLIENT_SHUTDOWN_ENABLE) ==
									 0UL))
    	    {
		goto deny;
            }
	
	    /* Expand ~ and ~user prefix if enaabled in options */
    	    rc = globus_l_gass_server_ez_tilde_expand(s->options,
                                              parsed_url.url_path,
                                              &path);
              
            if(strncmp(path, "/dev/saga", 9) == 0 && 
                    (s->options & GLOBUS_GASS_SERVER_EZ_STDOUT_ENABLE))
            {
                rc = s->fd; // the pipe handle!
            
                goto authorize;
            }
            else if(strncmp(path, "/dev/saga/", 9) == 0)
            {
                goto deny;
            }
                
    	    else if(strcmp(path, "/dev/globus_gass_client_shutdown") == 0)
    	    {
        	if(s->options & GLOBUS_GASS_SERVER_EZ_CLIENT_SHUTDOWN_ENABLE &&
           	   s->callback != GLOBUS_NULL)
        	{
            	    s->callback();
        	}

		goto deny;
    	    }
#ifdef TARGET_ARCH_WIN32
			// The call to open() in Windows defaults to text mode, so
			// we to override it.
			flags |= O_BINARY;
#endif
            rc = globus_libc_open(path, flags, 0600);

            if(rc < 0)
            {
                goto deny;
            }
	
	    authorize:
            globus_gass_transfer_authorize(request, 0);
	    if(s->options & GLOBUS_GASS_SERVER_EZ_LINE_BUFFER)
	    {
	        r=(globus_gass_server_ez_request_t *)globus_malloc(
				sizeof(globus_gass_server_ez_request_t));
		r->fd=rc;
		r->line_buffer=globus_malloc(80);
                r->line_buffer_used= 0UL;
        	r->line_buffer_length = 80UL;
        	r->linebuffer = GLOBUS_TRUE;

		globus_gass_transfer_receive_bytes(request,
						globus_malloc(1024),
						1024,
						1,
						globus_gass_server_ez_put_memory_done,
						r);
	    }
	    else
	    {
                globus_gass_transfer_receive_bytes(request,
                                               globus_malloc(1024),
                                               1024,
                                               1,
                                               globus_l_gass_server_ez_put_callback,
                                               (void *) rc);
	    }
            break;

          case GLOBUS_GASS_TRANSFER_REQUEST_TYPE_GET:
            flags = O_RDONLY;

			/* Expand ~ and ~user prefix if enaabled in options */
            rc = globus_l_gass_server_ez_tilde_expand(s->options,
                                              parsed_url.url_path,
                                              &path);

   	    if((s->options & GLOBUS_GASS_SERVER_EZ_READ_ENABLE) == 0UL)
    	    {
		goto deny;
    	    }
	   
	    if(stat(path, &statstruct)==0)
	    {
#ifdef TARGET_ARCH_WIN32
				// The call to open() in Windows defaults to text mode, 
				// so we to override it.
				flags |= O_BINARY;
#endif
                rc = globus_libc_open(path, flags, 0600);
		fstat(rc, &statstruct);
	    }
	    else
	    {
		globus_gass_transfer_deny(request, 404, "File Not Found");
		globus_gass_transfer_request_destroy(request);
		goto reregister;
	    }

            buf = globus_malloc(1024);
            amt = read(rc, buf, 1024);
            if(amt == -1)
            {
                globus_free(buf);
                goto deny;
            }
            globus_gass_transfer_authorize(request,
                                           statstruct.st_size);

            globus_gass_transfer_send_bytes(request,
                                            buf,
                                            amt,
                                            GLOBUS_FALSE,
                                            globus_l_gass_server_ez_get_callback,
                                            (void *) rc);
	  break;
	default:
	deny:
	  globus_gass_transfer_deny(request, 400, "Bad Request");
	  globus_gass_transfer_request_destroy(request);

	}

  reregister:
    globus_url_destroy(&parsed_url);

  reregister_nourl:
    globus_gass_transfer_register_listen(
				(globus_gass_transfer_listener_t) listener,
				globus_l_gass_server_ez_listen_callback,
				s->reqattr);

    if (path != GLOBUS_NULL) globus_free(path);

} /*globus_l_gass_server_ez_register_accept_callback*/
/******************************************************************************
Function: globus_l_gass_server_ez_put_memory_done()

Description: 

Parameters: 

Returns: 
******************************************************************************/
static void
globus_gass_server_ez_put_memory_done(void * arg,
                                       globus_gass_transfer_request_t request,
                                       globus_byte_t buffer[],
                                       globus_size_t receive_length,
				       globus_bool_t last_data)
{
    globus_gass_server_ez_request_t *r=GLOBUS_NULL;
    globus_size_t max_length;
    unsigned long lastnl, x;
    int status;
    const int buffer_length=1024;
    
    /* This callback handles line-buffered put requests. 
     */    

    r = (globus_gass_server_ez_request_t *)arg;

    status=globus_gass_transfer_request_get_status(request);
    lastnl = 0UL;


    /* find last \n in the buffer, since we are line-buffering */
    max_length=receive_length;
    for(x = max_length; x > 0UL; x--)
    {
	if(buffer[x-1] == '\n')
	{
	    lastnl = x;
	    break;
	}
    }
    
    if(status == GLOBUS_GASS_TRANSFER_REQUEST_PENDING && !last_data)
    {
	/* data arrived, and more will be available, so write up until
	 * the last \n we've received and save the rest
	 */
	if(r->line_buffer != GLOBUS_NULL &&
	   lastnl != 0UL &&
	    r->line_buffer_used != 0UL)
	{
	    globus_l_gass_server_ez_write(r->fd,
				r->line_buffer,
				r->line_buffer_used);
	    r->line_buffer_used = 0UL;
	}
	
	if(lastnl != 0UL)
	{
	    globus_l_gass_server_ez_write(r->fd,
				buffer,
				lastnl);
	}
	else
	{
	    lastnl = 0;
	}
	if(r->line_buffer_used + receive_length - lastnl >
	   r->line_buffer_length)
	{
	    r->line_buffer = (globus_byte_t *)
		realloc(r->line_buffer,
			r->line_buffer_used + receive_length - lastnl);
	    r->line_buffer_length = r->line_buffer_used + receive_length - lastnl;
	    memcpy(r->line_buffer + r->line_buffer_used,
		   buffer + lastnl,
		   receive_length - lastnl);
	    r->line_buffer_used += receive_length - lastnl;
	}
	else
	{
	    memcpy(r->line_buffer + r->line_buffer_used,
		   buffer + lastnl,
		   receive_length - lastnl);
	    r->line_buffer_used += receive_length - lastnl;
	}
	
	globus_gass_transfer_receive_bytes(request,
				  	   buffer,
					   buffer_length,
					   1UL,
					   globus_gass_server_ez_put_memory_done,
					   arg);
					
    }
    else
    {
	
	if(r->line_buffer != GLOBUS_NULL &&
	   r->line_buffer_used != 0UL)
	{
	    globus_l_gass_server_ez_write(r->fd,
				r->line_buffer,
				r->line_buffer_used);
	}
	if(receive_length != 0UL)
	{
	    globus_l_gass_server_ez_write(r->fd,
				buffer,
				receive_length);
	}

	    
	if(r->fd!=fileno(stdout) && r->fd!=fileno(stderr))
	{
    if(-1 == close(r->fd))
      printf("close error(fd: %d): %s\n", r->fd, strerror( errno ));
	}

	if(buffer != GLOBUS_NULL)
	{
	    globus_free(buffer);
	}  

	globus_gass_transfer_request_destroy(request);
		

	if(r->linebuffer)
	{
	    globus_free(r->line_buffer);
	} 
	globus_free(r);
    }
} /* globus_l_gass_server_ez_put_memory_done() */
static
void
globus_l_gram_streamer_local_poll(
    void *                              arg)
{
    globus_gram_streamer_monitor_t *    monitor = arg;
    int                                 rc;
    struct stat                         st;
    unsigned char *                     data;
    off_t                               data_size;
    globus_size_t                       amt;
    globus_bool_t                       last_data;
    int                                 i;
    char *                              save_state_file;
    globus_gram_stream_t *              streams[] =
    {
        &monitor->output_stream,
        &monitor->error_stream,
        NULL
    };
    globus_gram_stream_t *              stream;

    globus_mutex_lock(&monitor->mutex);

    /* Check if remote_io_file has changed */
    rc = stat("remote_io_file", &st);
    if (rc == 0)
    {
        if (st.st_mtime > monitor->remote_io_url_file_time)
        {
            /* Start the termination of the current output streams */
            for (i = 0; streams[i] != NULL; i++)
            {
	    	stream = streams[i];

                switch (stream->state)
                {
                case GLOBUS_GRAM_STREAM_NEW:
                case GLOBUS_GRAM_STREAM_ACTIVE:
                    globus_gass_transfer_fail(
                            stream->handle,
                            globus_l_gram_streamer_fail,
                            monitor);
                    stream->state = GLOBUS_GRAM_STREAM_RESTART;
                    break;
                case GLOBUS_GRAM_STREAM_FAIL:
                case GLOBUS_GRAM_STREAM_DONE:
                    stream->state = GLOBUS_GRAM_STREAM_RESTART_NEW;
                    stream->sent = 0;
                    stream->last_sent = GLOBUS_FALSE;
                    lseek(stream->fd, 0, SEEK_SET);
                    stream->handle = GLOBUS_NULL_HANDLE;
                    break;
                case GLOBUS_GRAM_STREAM_RESTART:
                case GLOBUS_GRAM_STREAM_RESTART_NEW:
                case GLOBUS_GRAM_STREAM_NONE:
                    break;
                }
            }
            monitor->remote_io_url_file_time = st.st_mtime;

            /* Load new state file */
            save_state_file = monitor->request.job_state_file;
            monitor->request.job_state_file = NULL;
            globus_gram_job_manager_request_free(&monitor->request);
            monitor->request.rsl = NULL;
            monitor->request.job_state_file = save_state_file;
            rc = globus_gram_job_manager_state_file_read(&monitor->request);
            if (rc != GLOBUS_SUCCESS)
            {
                fprintf(stderr, "%d:",
                        rc);
                exit(EXIT_FAILURE);
            }

            if (monitor->output_stream.source != NULL)
            {
                free(monitor->output_stream.source);
                monitor->output_stream.source = NULL;
            }
            if (monitor->output_stream.destination != NULL)
            {
                free(monitor->output_stream.destination);
                monitor->output_stream.destination = NULL;
            }
            if (monitor->error_stream.source != NULL)
            {
                free(monitor->error_stream.source);
                monitor->error_stream.source = NULL;
            }
            if (monitor->error_stream.destination != NULL)
            {
                free(monitor->error_stream.destination);
                monitor->error_stream.destination = NULL;
            }
            /* Re-evaluate RSL */
            rc = globus_l_gram_streamer_get_destinations(
                    monitor);
        }
    }

    /* On the first poll after everything is ready to restart, we'll reload
     * state information and reopen the stream
     */
    for (i = 0; streams[i] != NULL; i++)
    {
        stream = streams[i];

	if (stream->state == GLOBUS_GRAM_STREAM_RESTART_NEW)
	{
	    /* Re-open output stream */
	    if (stream->fd != -1 &&
		stream->destination != NULL)
	    {
		rc = globus_l_gram_streamer_open_destination(
			monitor,
			stream);
		if (rc == GLOBUS_SUCCESS)
		{
		    stream->state = GLOBUS_GRAM_STREAM_NEW;
		}
		else
		{
		    stream->state = GLOBUS_GRAM_STREAM_FAIL;
		}
	    }
	    else
	    {
		stream->state = GLOBUS_GRAM_STREAM_DONE;
	    }
	}
    }

    /* Only queue data if the transfer is alive */
    for (i = 0; streams[i] != NULL; i++)
    {
        stream = streams[i];

        if (stream->state == GLOBUS_GRAM_STREAM_ACTIVE &&
            (fstat(stream->fd, &st) == 0))
        {
            data_size = st.st_size - stream->sent;
            if (data_size > STREAMER_BLOCKSIZE)
            {
                data_size = STREAMER_BLOCKSIZE;
            }
            amt = 0;

            data = NULL;
            if (data_size > 0)
            {
                data = malloc((size_t) data_size);

                do
                {
                    rc = read(stream->fd, data + amt, data_size - amt);
                    if (rc < 0)
                    {
                        if (errno != EINTR)
                        {
                            break;
                        }
                    }
                    else if (rc == 0)
                    {
                        break;
                    }
                    else
                    {
                        amt += rc;
                    }
                }
                while (amt < data_size);
            }
            if (amt > 0 || ((monitor->pid_count == 0) && (!stream->last_sent)))
            {
                stream->sent += amt;
                stream->blocks++;

                last_data = (monitor->pid_count == 0) &&
                            (stream->sent == st.st_size);

                rc = globus_gass_transfer_send_bytes(
                        stream->handle,
                        (data == NULL) ? malloc(1) : data,
                        amt,
                        last_data,
                        globus_l_gram_streamer_data_callback,
                        monitor);
                switch (rc)
                {
                case GLOBUS_SUCCESS:
                    stream->last_sent = last_data;
                    break;
                case GLOBUS_GASS_TRANSFER_ERROR_NULL_POINTER:
                    fprintf(stderr, "NULL pointer");
                    exit(EXIT_FAILURE);
                    break;
                case GLOBUS_GASS_TRANSFER_ERROR_INVALID_USE:
                    stream->last_sent = GLOBUS_TRUE;
                    globus_gass_transfer_request_destroy(stream->handle);
                    stream->state = GLOBUS_GRAM_STREAM_FAIL;
                    break;
                case GLOBUS_GASS_TRANSFER_ERROR_NOT_INITIALIZED:
                    fprintf(stderr, "Not initialized");
                    exit(EXIT_FAILURE);
                    break;
                case GLOBUS_GASS_TRANSFER_REQUEST_FAILED:
                    fprintf(stderr, "Failed ");
                    exit(EXIT_FAILURE);

                }
            }
        }
    }
    globus_mutex_unlock(&monitor->mutex);
}