Skip to content
Snippets Groups Projects
sendf.c 9.11 KiB
Newer Older
  • Learn to ignore specific revisions
  • Daniel Stenberg's avatar
    Daniel Stenberg committed
    /*****************************************************************************
     *                                  _   _ ____  _     
     *  Project                     ___| | | |  _ \| |    
     *                             / __| | | | |_) | |    
     *                            | (__| |_| |  _ <| |___ 
     *                             \___|\___/|_| \_\_____|
     *
    
     * Copyright (C) 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     *
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     * In order to be useful for every potential user, curl and libcurl are
     * dual-licensed under the MPL and the MIT/X-derivate licenses.
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     *
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     * You may opt to use, copy, modify, merge, publish, distribute and/or sell
     * copies of the Software, and permit persons to whom the Software is
     * furnished to do so, under the terms of the MPL or the MIT/X-derivate
     * licenses. You may pick one of these licenses.
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     *
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     * KIND, either express or implied.
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     *
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
     * $Id$
     *****************************************************************************/
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #include <stdio.h>
    #include <stdarg.h>
    #include <stdlib.h>
    
    #include <errno.h>
    
    
    #ifdef HAVE_SYS_TYPES_H
    #include <sys/types.h>
    #endif
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
    #ifdef HAVE_SYS_SOCKET_H
    #include <sys/socket.h>	/* required for send() & recv() prototypes */
    #endif
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #ifdef HAVE_UNISTD_H
    #include <unistd.h>
    #endif
    #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
    #include <winsock.h>
    #endif
    
    #include <curl/curl.h>
    #include "urldata.h"
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #define _MPRINTF_REPLACE /* use the internal *printf() functions */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    #include <curl/mprintf.h>
    
    
    #ifdef KRB4
    #include "security.h"
    #endif
    
    /* The last #include file should be: */
    #ifdef MALLOCDEBUG
    #include "memdebug.h"
    #endif
    
    /* returns last node in linked list */
    static struct curl_slist *slist_get_last(struct curl_slist *list)
    {
    	struct curl_slist	*item;
    
    	/* if caller passed us a NULL, return now */
    	if (!list)
    		return NULL;
    
    	/* loop through to find the last item */
    	item = list;
    	while (item->next) {
    		item = item->next;
    	}
    	return item;
    }
    
    /* append a struct to the linked list. It always retunrs the address of the
     * first record, so that you can sure this function as an initialization
     * function as well as an append function. If you find this bothersome,
     * then simply create a separate _init function and call it appropriately from
     * within the proram. */
    struct curl_slist *curl_slist_append(struct curl_slist *list,
                                         const char *data)
    {
    	struct curl_slist	*last;
    	struct curl_slist	*new_item;
    
    	new_item = (struct curl_slist *) malloc(sizeof(struct curl_slist));
    	if (new_item) {
    		new_item->next = NULL;
    		new_item->data = strdup(data);
    	}
    	else {
    		fprintf(stderr, "Cannot allocate memory for QUOTE list.\n");
    		return NULL;
    	}
    
    	if (list) {
    		last = slist_get_last(list);
    		last->next = new_item;
    		return list;
    	}
    
    	/* if this is the first item, then new_item *is* the list */
    	return new_item;
    }
    
    /* be nice and clean up resources */
    void curl_slist_free_all(struct curl_slist *list)
    {
    	struct curl_slist	*next;
    	struct curl_slist	*item;
    
    	if (!list)
    		return;
    
    	item = list;
    	do {
    		next = item->next;
    		
    		if (item->data) {
    			free(item->data);
    		}
    		free(item);
    		item = next;
    	} while (next);
    }
    
    
    
    /* Curl_infof() is for info message along the way */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
    void Curl_infof(struct SessionHandle *data, const char *fmt, ...)
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    {
      va_list ap;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        va_start(ap, fmt);
    
        fputs("* ", data->set.err);
        vfprintf(data->set.err, fmt, ap);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
        va_end(ap);
      }
    }
    
    
    /* Curl_failf() is for messages stating why we failed.
     * The message SHALL NOT include any LF or CR.
     */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    
    
    void Curl_failf(struct SessionHandle *data, const char *fmt, ...)
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    {
      va_list ap;
      va_start(ap, fmt);
    
      if(data->set.errorbuffer && !data->state.errorbuf) {
    
        vsnprintf(data->set.errorbuffer, CURL_ERROR_SIZE, fmt, ap);
    
        data->state.errorbuf = TRUE; /* wrote error string */
      }
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      va_end(ap);
    }
    
    
    /* Curl_sendf() sends formated data to the server */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    CURLcode Curl_sendf(int sockfd, struct connectdata *conn,
                        const char *fmt, ...)
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
    {
    
      struct SessionHandle *data = conn->data;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      char *s;
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      va_list ap;
      va_start(ap, fmt);
    
      s = vaprintf(fmt, ap); /* returns an allocated string */
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      va_end(ap);
      if(!s)
    
        return CURLE_OUT_OF_MEMORY; /* failure */
    
    
      if(data->set.verbose)
        fprintf(data->set.err, "> %s", s);
    
      bytes_written=0;
      write_len = strlen(s);
      sptr = s;
    
      do {
        /* Write the buffer to the socket */
        res = Curl_write(conn, sockfd, sptr, write_len, &bytes_written);
    
        if(CURLE_OK != res)
          break;
    
        if(bytes_written != write_len) {
          /* if not all was written at once, we must advance the pointer, decrease
             the size left and try again! */
          write_len -= bytes_written;
          sptr += bytes_written;
        }
        else
          break;
    
      } while(1);
    
    Daniel Stenberg's avatar
    Daniel Stenberg committed
      free(s); /* free the output string */
    
    /*
     * Curl_write() is an internal write function that sends plain (binary) data
     * to the server. Works with plain sockets, SSL or kerberos.
     *
     */
    CURLcode Curl_write(struct connectdata *conn, int sockfd,
                        void *mem, size_t len,
    
    #ifdef USE_SSLEAY
    
      /* SSL_write() is said to return 'int' while write() and send() returns
         'size_t' */
    
      if (conn->ssl.use) {
    
        int err;
        int rc = SSL_write(conn->ssl.handle, mem, len);
    
        if(rc < 0) {
          err = SSL_get_error(conn->ssl.handle, rc);
        
          switch(err) {
          case SSL_ERROR_WANT_READ:
          case SSL_ERROR_WANT_WRITE:
            /* this is basicly the EWOULDBLOCK equivalent */
            *written = 0;
            return CURLE_OK;
    
          /* a true error */
          failf(conn->data, "SSL_write() return error %d\n", err);
          return CURLE_WRITE_ERROR;
    
        bytes_written = rc;
    
      else {
    #endif
    #ifdef KRB4
        if(conn->sec_complete) {
    
          bytes_written = Curl_sec_write(conn, sockfd, mem, len);
    
        }
        else
    #endif /* KRB4 */
    
          bytes_written = swrite(sockfd, mem, len);
    
          if(WSAEWOULDBLOCK == GetLastError())
    
    #else
          if(EWOULDBLOCK == errno)
    #endif
          {
            /* this is just a case of EWOULDBLOCK */
            *written=0;
            return CURLE_OK;
          }
        }
    
    #ifdef USE_SSLEAY
      }
    #endif
    
    
      *written = bytes_written;
    
      return (-1 != bytes_written)?CURLE_OK:CURLE_WRITE_ERROR;
    
    /* client_write() sends data to the write callback(s)
    
       The bit pattern defines to what "streams" to write to. Body and/or header.
       The defines are in sendf.h of course.
     */
    
    CURLcode Curl_client_write(struct SessionHandle *data,
    
    {
      size_t wrote;
    
      if(0 == len)
        len = strlen(ptr);
    
      if(type & CLIENTWRITE_BODY) {
    
        wrote = data->set.fwrite(ptr, 1, len, data->set.out);
    
        if(wrote != len) {
          failf (data, "Failed writing body");
          return CURLE_WRITE_ERROR;
        }
      }
    
         (data->set.fwrite_header || data->set.writeheader) ) {
    
        /*
         * Write headers to the same callback or to the especially setup
         * header callback function (added after version 7.7.1).
         */
        curl_write_callback writeit=
    
          data->set.fwrite_header?data->set.fwrite_header:data->set.fwrite;
    
        wrote = writeit(ptr, 1, len, data->set.writeheader);
    
        if(wrote != len) {
          failf (data, "Failed writing header");
          return CURLE_WRITE_ERROR;
        }
      }
      
      return CURLE_OK;
    }
    
    
    /*
     * Internal read-from-socket function. This is meant to deal with plain
     * sockets, SSL sockets and kerberos sockets.
    
     *
     * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return
     * a regular CURLcode value.
    
    int Curl_read(struct connectdata *conn,
                  int sockfd,
                  char *buf,
                  size_t buffersize,
                  ssize_t *n)
    
    
    #ifdef USE_SSLEAY
    
      if (conn->ssl.use) {
    
          nread = SSL_read(conn->ssl.handle, buf, buffersize);
    
    
          err = SSL_get_error(conn->ssl.handle, nread);
    
          switch(err) {
          case SSL_ERROR_NONE: /* this is not an error */
          case SSL_ERROR_ZERO_RETURN: /* no more data */
            loop=0; /* get out of loop */
            break;
          case SSL_ERROR_WANT_READ:
          case SSL_ERROR_WANT_WRITE:
            /* if there's data pending, then we re-invoke SSL_read() */
            break;
          }
    
        if(loop && SSL_pending(conn->ssl.handle))
          return -1; /* basicly EWOULDBLOCK */
    
      }
      else {
    #endif
    #ifdef KRB4
        if(conn->sec_complete)
    
          nread = Curl_sec_read(conn, sockfd, buf, buffersize);
    
        else
    #endif
          nread = sread (sockfd, buf, buffersize);
    
          if(WSAEWOULDBLOCK == GetLastError())
    
    #ifdef USE_SSLEAY
      }
    #endif /* USE_SSLEAY */
      *n = nread;
      return CURLE_OK;
    }
    
    
    
    /*
     * local variables:
     * eval: (load-file "../curl-mode.el")
     * end:
    
     * vim600: fdm=marker
     * vim: et sw=2 ts=2 sts=2 tw=78