History of Changes
+** curl 7.7 DOES NOT currently WORK. **
+
+Daniel (20 February 2001)
+- Added the docs/examples/win32sockets.c file for our windows friends.
+
+- Linus Nielsen Feltzing provided brand new TELNET functionality and
+ improvements:
+
+ * Negotiation is now passive. Curl does not negotiate until the peer does.
+ * Possibility to set negotiation options on the command line, currently only
+ XDISPLOC, TTYPE and NEW_ENVIRON (called NEW_ENV).
+ * Now sends the USER environment variable if the -u switch is used.
+ * Use -t to set telnet options (Linus even updated the man page, awesome!)
+
+- Haven't done this big changes to curl for a while. Moved around a lot of
+ struct fields and stuff to make multiple connections get connection specific
+ data in separate structs so that they can co-exist in a nice way. See the
+ mailing lists for discussions around how this is gonna be implemented. Docs
+ and more will follow.
+
+ Studied the HTTP RFC to find out better how persistant connections should
+ work. Seems cool enough.
+
+Daniel (19 February 2001)
+- Bob Schader brought me two files that help set up a MS VC++ libcurl project
+ easier. He also provided me with an up-to-date libcurl.def file.
+
+- I moved a bunch of prototypes from the public <curl/curl.h> file to the
+ library private urldata.h. This is because of the upcoming changes. The
+ low level interface is no longer being planned to become reality.
+
+Daniel (15 February 2001)
+- CURLOPT_POST is not required anymore. Just setting the POST string with
+ CURLOPT_POSTFIELDS will switch on the HTTP POST. Most other things in
+ libcurl already works this way, i.e they require only the parameter to
+ switch on a feature so I think this works well with the rest. Setting a NULL
+ string switches off the POST again.
+
+- Excellent suggestions from Rich Gray, Rick Jones, Johan Nilsson and Bjorn
+ Reese helped me define a way how to incorporate persistant connections into
+ libcurl in a very smooth way. If done right, no change may have to be made
+ to older programs and they will just start using persistant connections when
+ applicable!
+
+Daniel (13 February 2001)
+- Changed the word 'timeouted' to 'timed out' in two different error messages.
+ Suggested by Larry Fahnoe.
+
Version 7.6.1
Daniel (9 February 2001)
- compiles on win32
- redirectable stderr
- use selected network interface for outgoing traffic
+ - IPv6 support
HTTP
- GET
- POST
- multipart POST
- authentication
- - resume
+ - resume (both GET and PUT)
- follow redirects
- maximum amount of redirects to follow
- custom HTTP request
When used with -s it makes curl show error message if it fails.
If this option is used twice, the second will again disable show error.
-.IP "-t/--upload"
-.B Deprecated. Use '-T -' instead.
-Transfer the stdin data to the specified file. Curl will read
-everything from stdin until EOF and store with the supplied name. If
-this is used on a http(s) server, the PUT command will be used.
+.IP "-t/--telnet-option <OPT=val>"
+Pass options to the telnet protocol. Supported options are:
+
+TTYPE=<term> Sets the terminal type.
+
+XDISPLOC=<X display> Sets the X display location.
+
+NEW_ENV=<var,val> Sets an environment variable.
.IP "-T/--upload-file <file>"
Like -t, but this transfers the specified local file. If there is no
file part in the specified URL, Curl will append the local file
- Lars J. Aas <larsa@sim.no>
- Jörn Hartroth <Joern.Hartroth@computer.org>
- Matthew Clarke <clamat@van.maves.ca>
- - Linus Nielsen <Linus.Nielsen@haxx.se>
+ - Linus Nielsen Feltzing <linus@haxx.se>
- Felix von Leitner <felix@convergence.de>
- Dan Zitter <dzitter@zitter.net>
- Jongki Suwandi <Jongki.Suwandi@eng.sun.com>
CURLE_BAD_PASSWORD_ENTERED, /* when the my_getpass() returns fail */
CURLE_TOO_MANY_REDIRECTS , /* catch endless re-direct loops */
+ CURLE_UNKNOWN_TELNET_OPTION , /* User specified an unknown option */
+ CURLE_TELNET_OPTION_SYNTAX , /* Malformed telnet option */
+
CURL_LAST
} CURLcode;
document! Pass a NULL to shut it off. */
CINIT(FILETIME, OBJECTPOINT, 69),
+ /* This points to a linked list of telnet options */
+ CINIT(TELNETOPTIONS, OBJECTPOINT, 70),
+
CURLOPT_LASTENTRY /* the last unusued */
} CURLoption;
char *curl_version(void);
/* This is the version number */
-#define LIBCURL_VERSION "7.6.1"
-#define LIBCURL_VERSION_NUM 0x070601
+#define LIBCURL_VERSION "7.7-alpha1"
+#define LIBCURL_VERSION_NUM 0x070000
/* linked-list structure for the CURLOPT_QUOTE option (and other) */
struct curl_slist {
*/
CURLcode curl_getinfo(CURL *curl, CURLINFO info, ...);
+
+typedef enum {
+ CURLCLOSEPOLICY_NONE, /* first, never use this */
+
+ CURLCLOSEPOLICY_OLDEST,
+ CURLCLOSEPOLICY_LEAST_RECENTLY_USED,
+ CURLCLOSEPOLICY_LEAST_TRAFFIC,
+ CURLCLOSEPOLICY_SLOWEST,
+ CURLCLOSEPOLICY_CALLBACK,
+
+ CURLCLOSEPOLICY_LAST /* last, never use this */
+} curl_closepolicy;
+
+
#ifdef __cplusplus
}
#endif
nth = atoi(nthdef);
}
- Curl_sendf(data->firstsocket, conn,
+ Curl_sendf(conn->firstsocket, conn,
"CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n"
"MATCH "
"%s " /* database */
word
);
- result = Curl_Transfer(conn, data->firstsocket, -1, FALSE, bytecount,
+ result = Curl_Transfer(conn, conn->firstsocket, -1, FALSE, bytecount,
-1, NULL); /* no upload */
if(result)
nth = atoi(nthdef);
}
- Curl_sendf(data->firstsocket, conn,
+ Curl_sendf(conn->firstsocket, conn,
"CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n"
"DEFINE "
"%s " /* database */
word
);
- result = Curl_Transfer(conn, data->firstsocket, -1, FALSE, bytecount,
+ result = Curl_Transfer(conn, conn->firstsocket, -1, FALSE, bytecount,
-1, NULL); /* no upload */
if(result)
if (ppath[i] == ':')
ppath[i] = ' ';
}
- Curl_sendf(data->firstsocket, conn,
+ Curl_sendf(conn->firstsocket, conn,
"CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\n"
"%s\n"
"QUIT\n",
ppath);
- result = Curl_Transfer(conn, data->firstsocket, -1, FALSE, bytecount,
+ result = Curl_Transfer(conn, conn->firstsocket, -1, FALSE, bytecount,
-1, NULL);
if(result)
static CURLcode AllowServerConnect(struct UrlData *data,
+ struct connectdata *conn,
int sock)
{
fd_set rdset;
}
infof(data, "Connection accepted from server\n");
- data->secondarysocket = s;
+ conn->secondarysocket = s;
}
break;
}
return CURLE_OUT_OF_MEMORY;
memset(ftp, 0, sizeof(struct FTP));
- data->proto.ftp = ftp;
+ conn->proto.ftp = ftp;
/* get some initial data into the ftp struct */
ftp->bytecountp = &conn->bytecount;
if (data->bits.tunnel_thru_httpproxy) {
/* We want "seamless" FTP operations through HTTP proxy tunnel */
- result = Curl_ConnectHTTPProxyTunnel(conn, data->firstsocket,
- data->hostname, data->remote_port);
+ result = Curl_ConnectHTTPProxyTunnel(conn, conn->firstsocket,
+ conn->hostname, conn->remote_port);
if(CURLE_OK != result)
return result;
}
/* The first thing we do is wait for the "220*" line: */
- nread = Curl_GetFTPResponse(data->firstsocket, buf, conn, &ftpcode);
+ nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
set a valid level */
sec_request_prot(conn, data->krb4_level);
- data->cmdchannel = fdopen(data->firstsocket, "w");
+ data->cmdchannel = fdopen(conn->firstsocket, "w");
if(sec_login(conn) != 0)
infof(data, "Logging in with password in cleartext!\n");
#endif
/* send USER */
- ftpsendf(data->firstsocket, conn, "USER %s", ftp->user);
+ ftpsendf(conn->firstsocket, conn, "USER %s", ftp->user);
/* wait for feedback */
- nread = Curl_GetFTPResponse(data->firstsocket, buf, conn, &ftpcode);
+ nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
else if(ftpcode == 331) {
/* 331 Password required for ...
(the server requires to send the user's password too) */
- ftpsendf(data->firstsocket, conn, "PASS %s", ftp->passwd);
- nread = Curl_GetFTPResponse(data->firstsocket, buf, conn, &ftpcode);
+ ftpsendf(conn->firstsocket, conn, "PASS %s", ftp->passwd);
+ nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
CURLcode Curl_ftp_done(struct connectdata *conn)
{
struct UrlData *data = conn->data;
- struct FTP *ftp = data->proto.ftp;
+ struct FTP *ftp = conn->proto.ftp;
size_t nread;
char *buf = data->buffer; /* this is our buffer */
struct curl_slist *qitem; /* QUOTE item */
}
}
#ifdef KRB4
- sec_fflush_fd(conn, data->secondarysocket);
+ sec_fflush_fd(conn, conn->secondarysocket);
#endif
/* shut down the socket to inform the server we're done */
- sclose(data->secondarysocket);
- data->secondarysocket = -1;
+ sclose(conn->secondarysocket);
+ conn->secondarysocket = -1;
if(!data->bits.no_body) {
/* now let's see what the server says about the transfer we
just performed: */
- nread = Curl_GetFTPResponse(data->firstsocket, buf, conn, &ftpcode);
+ nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
while (qitem) {
/* Send string */
if (qitem->data) {
- ftpsendf(data->firstsocket, conn, "%s", qitem->data);
+ ftpsendf(conn->firstsocket, conn, "%s", qitem->data);
- nread = Curl_GetFTPResponse(data->firstsocket, buf, conn, &ftpcode);
+ nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
struct curl_slist *qitem; /* QUOTE item */
/* the ftp struct is already inited in ftp_connect() */
- struct FTP *ftp = data->proto.ftp;
+ struct FTP *ftp = conn->proto.ftp;
long *bytecountp = ftp->bytecountp;
int ftpcode; /* for ftp status */
while (qitem) {
/* Send string */
if (qitem->data) {
- ftpsendf(data->firstsocket, conn, "%s", qitem->data);
+ ftpsendf(conn->firstsocket, conn, "%s", qitem->data);
- nread = Curl_GetFTPResponse(data->firstsocket, buf, conn, &ftpcode);
+ nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
/* change directory first! */
if(ftp->dir && ftp->dir[0]) {
- ftpsendf(data->firstsocket, conn, "CWD %s", ftp->dir);
- nread = Curl_GetFTPResponse(data->firstsocket, buf, conn, &ftpcode);
+ ftpsendf(conn->firstsocket, conn, "CWD %s", ftp->dir);
+ nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
if(data->bits.get_filetime && ftp->file) {
/* we have requested to get the modified-time of the file, this is yet
again a grey area as the MDTM is not kosher RFC959 */
- ftpsendf(data->firstsocket, conn, "MDTM %s", ftp->file);
+ ftpsendf(conn->firstsocket, conn, "MDTM %s", ftp->file);
- nread = Curl_GetFTPResponse(data->firstsocket, buf, conn, &ftpcode);
+ nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
/* Some servers return different sizes for different modes, and thus we
must set the proper type before we check the size */
- ftpsendf(data->firstsocket, conn, "TYPE %s",
+ ftpsendf(conn->firstsocket, conn, "TYPE %s",
(data->bits.ftp_ascii)?"A":"I");
- nread = Curl_GetFTPResponse(data->firstsocket, buf, conn, &ftpcode);
+ nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
CURLE_FTP_COULDNT_SET_BINARY;
}
- ftpsendf(data->firstsocket, conn, "SIZE %s", ftp->file);
+ ftpsendf(conn->firstsocket, conn, "SIZE %s", ftp->file);
- nread = Curl_GetFTPResponse(data->firstsocket, buf, conn, &ftpcode);
+ nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
* I believe we should use the same address as the control connection.
*/
sslen = sizeof(ss);
- if (getsockname(data->firstsocket, (struct sockaddr *)&ss, &sslen) < 0)
+ if (getsockname(conn->firstsocket, (struct sockaddr *)&ss, &sslen) < 0)
return CURLE_FTP_PORT_FAILED;
if (getnameinfo((struct sockaddr *)&ss, sslen, hbuf, sizeof(hbuf), NULL, 0,
if (q)
*q = '\0';
}
- ftpsendf(data->firstsocket, conn, "%s |%d|%s|%s|", *modep, eprtaf,
+ ftpsendf(conn->firstsocket, conn, "%s |%d|%s|%s|", *modep, eprtaf,
portmsgbuf, tmp);
} else if (strcmp(*modep, "LPRT") == 0 || strcmp(*modep, "PORT") == 0) {
int i;
goto again;
}
}
- ftpsendf(data->firstsocket, conn, "%s %s", *modep, portmsgbuf);
+ ftpsendf(conn->firstsocket, conn, "%s %s", *modep, portmsgbuf);
}
- nread = Curl_GetFTPResponse(data->firstsocket, buf, conn, &ftpcode);
+ nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if (nread < 0)
return CURLE_OPERATION_TIMEOUTED;
/* we set the secondary socket variable to this for now, it
is only so that the cleanup function will close it in case
we fail before the true secondary stuff is made */
- data->secondarysocket = portsock;
+ conn->secondarysocket = portsock;
memset((char *)&sa, 0, sizeof(sa));
memcpy((char *)&sa.sin_addr,
sscanf( inet_ntoa(in), "%hu.%hu.%hu.%hu",
&ip[0], &ip[1], &ip[2], &ip[3]);
#endif
- ftpsendf(data->firstsocket, conn, "PORT %d,%d,%d,%d,%d,%d",
+ ftpsendf(conn->firstsocket, conn, "PORT %d,%d,%d,%d,%d,%d",
ip[0], ip[1], ip[2], ip[3],
porttouse >> 8,
porttouse & 255);
}
- nread = Curl_GetFTPResponse(data->firstsocket, buf, conn, &ftpcode);
+ nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
int modeoff;
for (modeoff = 0; mode[modeoff]; modeoff++) {
- ftpsendf(data->firstsocket, conn, mode[modeoff]);
- nread = Curl_GetFTPResponse(data->firstsocket, buf, conn, &ftpcode);
+ ftpsendf(conn->firstsocket, conn, mode[modeoff]);
+ nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
}
#ifdef ENABLE_IPV6
- data->secondarysocket = -1;
+ conn->secondarysocket = -1;
for (ai = res; ai; ai = ai->ai_next) {
/* XXX for now, we can do IPv4 only */
if (ai->ai_family != AF_INET)
continue;
- data->secondarysocket = socket(ai->ai_family, ai->ai_socktype,
+ conn->secondarysocket = socket(ai->ai_family, ai->ai_socktype,
ai->ai_protocol);
- if (data->secondarysocket < 0)
+ if (conn->secondarysocket < 0)
continue;
if(data->bits.verbose) {
}
}
- if (connect(data->secondarysocket, ai->ai_addr, ai->ai_addrlen) < 0) {
- close(data->secondarysocket);
- data->secondarysocket = -1;
+ if (connect(conn->secondarysocket, ai->ai_addr, ai->ai_addrlen) < 0) {
+ close(conn->secondarysocket);
+ conn->secondarysocket = -1;
continue;
}
break;
}
- if (data->secondarysocket < 0) {
+ if (conn->secondarysocket < 0) {
failf(data, strerror(errno));
return CURLE_FTP_CANT_RECONNECT;
}
#else
- data->secondarysocket = socket(AF_INET, SOCK_STREAM, 0);
+ conn->secondarysocket = socket(AF_INET, SOCK_STREAM, 0);
memset((char *) &serv_addr, '\0', sizeof(serv_addr));
memcpy((char *)&(serv_addr.sin_addr), he->h_addr, he->h_length);
if(hostdataptr)
free(hostdataptr);
- if (connect(data->secondarysocket, (struct sockaddr *) &serv_addr,
+ if (connect(conn->secondarysocket, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0) {
switch(errno) {
#ifdef ECONNREFUSED
if (data->bits.tunnel_thru_httpproxy) {
/* We want "seamless" FTP operations through HTTP proxy tunnel */
- result = Curl_ConnectHTTPProxyTunnel(conn, data->secondarysocket,
+ result = Curl_ConnectHTTPProxyTunnel(conn, conn->secondarysocket,
newhost, newport);
if(CURLE_OK != result)
return result;
if(data->bits.upload) {
/* Set type to binary (unless specified ASCII) */
- ftpsendf(data->firstsocket, conn, "TYPE %s",
+ ftpsendf(conn->firstsocket, conn, "TYPE %s",
(data->bits.ftp_ascii)?"A":"I");
- nread = Curl_GetFTPResponse(data->firstsocket, buf, conn, &ftpcode);
+ nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
/* we could've got a specified offset from the command line,
but now we know we didn't */
- ftpsendf(data->firstsocket, conn, "SIZE %s", ftp->file);
+ ftpsendf(conn->firstsocket, conn, "SIZE %s", ftp->file);
- nread = Curl_GetFTPResponse(data->firstsocket, buf, conn, &ftpcode);
+ nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
/* Send everything on data->in to the socket */
if(data->bits.ftp_append)
/* we append onto the file instead of rewriting it */
- ftpsendf(data->firstsocket, conn, "APPE %s", ftp->file);
+ ftpsendf(conn->firstsocket, conn, "APPE %s", ftp->file);
else
- ftpsendf(data->firstsocket, conn, "STOR %s", ftp->file);
+ ftpsendf(conn->firstsocket, conn, "STOR %s", ftp->file);
- nread = Curl_GetFTPResponse(data->firstsocket, buf, conn, &ftpcode);
+ nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
}
if(data->bits.ftp_use_port) {
- result = AllowServerConnect(data, portsock);
+ result = AllowServerConnect(data, conn, portsock);
if( result )
return result;
}
Curl_pgrsSetUploadSize(data, data->infilesize);
result = Curl_Transfer(conn, -1, -1, FALSE, NULL, /* no download */
- data->secondarysocket, bytecountp);
+ conn->secondarysocket, bytecountp);
if(result)
return result;
dirlist = TRUE;
/* Set type to ASCII */
- ftpsendf(data->firstsocket, conn, "TYPE A");
+ ftpsendf(conn->firstsocket, conn, "TYPE A");
- nread = Curl_GetFTPResponse(data->firstsocket, buf, conn, &ftpcode);
+ nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
better used since the LIST command output is not specified or
standard in any way */
- ftpsendf(data->firstsocket, conn, "%s",
+ ftpsendf(conn->firstsocket, conn, "%s",
data->customrequest?data->customrequest:
(data->bits.ftp_list_only?"NLST":"LIST"));
}
else {
/* Set type to binary (unless specified ASCII) */
- ftpsendf(data->firstsocket, conn, "TYPE %s",
+ ftpsendf(conn->firstsocket, conn, "TYPE %s",
(data->bits.ftp_ascii)?"A":"I");
- nread = Curl_GetFTPResponse(data->firstsocket, buf, conn, &ftpcode);
+ nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
* of the file we're gonna get. If we can get the size, this is by far
* the best way to know if we're trying to resume beyond the EOF. */
- ftpsendf(data->firstsocket, conn, "SIZE %s", ftp->file);
+ ftpsendf(conn->firstsocket, conn, "SIZE %s", ftp->file);
- nread = Curl_GetFTPResponse(data->firstsocket, buf, conn, &ftpcode);
+ nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
infof(data, "Instructs server to resume from offset %d\n",
data->resume_from);
- ftpsendf(data->firstsocket, conn, "REST %d", data->resume_from);
+ ftpsendf(conn->firstsocket, conn, "REST %d", data->resume_from);
- nread = Curl_GetFTPResponse(data->firstsocket, buf, conn, &ftpcode);
+ nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
}
}
- ftpsendf(data->firstsocket, conn, "RETR %s", ftp->file);
+ ftpsendf(conn->firstsocket, conn, "RETR %s", ftp->file);
}
- nread = Curl_GetFTPResponse(data->firstsocket, buf, conn, &ftpcode);
+ nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
size = downloadsize;
if(data->bits.ftp_use_port) {
- result = AllowServerConnect(data, portsock);
+ result = AllowServerConnect(data, conn, portsock);
if( result )
return result;
}
infof(data, "Getting file with size: %d\n", size);
/* FTP download: */
- result=Curl_Transfer(conn, data->secondarysocket, size, FALSE,
+ result=Curl_Transfer(conn, conn->secondarysocket, size, FALSE,
bytecountp,
-1, NULL); /* no upload here */
if(result)
int dirlength=0; /* 0 forces strlen() */
/* the ftp struct is already inited in ftp_connect() */
- ftp = data->proto.ftp;
+ ftp = conn->proto.ftp;
/* We split the path into dir and file parts *before* we URLdecode
it */
if (conn->protocol & PROT_HTTPS) {
if (data->bits.httpproxy) {
/* HTTPS through a proxy can only be done with a tunnel */
- result = Curl_ConnectHTTPProxyTunnel(conn, data->firstsocket,
- data->hostname, data->remote_port);
+ result = Curl_ConnectHTTPProxyTunnel(conn, conn->firstsocket,
+ conn->hostname, conn->remote_port);
if(CURLE_OK != result)
return result;
}
/* now, perform the SSL initialization for this socket */
- if(Curl_SSLConnect(data))
+ if(Curl_SSLConnect(conn))
return CURLE_SSL_CONNECT_ERROR;
}
if(data->bits.user_passwd && !data->bits.this_is_a_follow) {
/* Authorization: is requested, this is not a followed location, get the
original host name */
- data->auth_host = strdup(data->hostname);
+ data->auth_host = strdup(conn->hostname);
}
return CURLE_OK;
struct HTTP *http;
data=conn->data;
- http=data->proto.http;
+ http=conn->proto.http;
if(data->bits.http_formpost) {
*bytecount = http->readbytecount + http->writebytecount;
if(!http)
return CURLE_OUT_OF_MEMORY;
memset(http, 0, sizeof(struct HTTP));
- data->proto.http = http;
+ conn->proto.http = http;
if ( (conn->protocol&(PROT_HTTP|PROT_FTP)) &&
data->bits.upload) {
host due to a location-follow, we do some weirdo checks here */
if(!data->bits.this_is_a_follow ||
!data->auth_host ||
- strequal(data->auth_host, data->hostname)) {
+ strequal(data->auth_host, conn->hostname)) {
sprintf(data->buffer, "%s:%s", data->user, data->passwd);
if(Curl_base64_encode(data->buffer, strlen(data->buffer),
&authorization) >= 0) {
Curl_pgrsSetUploadSize(data, http->postsize);
data->request_size =
- add_buffer_send(data->firstsocket, conn, req_buffer);
- result = Curl_Transfer(conn, data->firstsocket, -1, TRUE,
+ add_buffer_send(conn->firstsocket, conn, req_buffer);
+ result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE,
&http->readbytecount,
- data->firstsocket,
+ conn->firstsocket,
&http->writebytecount);
if(result) {
Curl_FormFree(http->sendit); /* free that whole lot */
/* this sends the buffer and frees all the buffer resources */
data->request_size =
- add_buffer_send(data->firstsocket, conn, req_buffer);
+ add_buffer_send(conn->firstsocket, conn, req_buffer);
/* prepare for transfer */
- result = Curl_Transfer(conn, data->firstsocket, -1, TRUE,
+ result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE,
&http->readbytecount,
- data->firstsocket,
+ conn->firstsocket,
&http->writebytecount);
if(result)
return result;
/* issue the request */
data->request_size =
- add_buffer_send(data->firstsocket, conn, req_buffer);
+ add_buffer_send(conn->firstsocket, conn, req_buffer);
/* HTTP GET/HEAD download: */
- result = Curl_Transfer(conn, data->firstsocket, -1, TRUE, bytecount,
+ result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE, bytecount,
-1, NULL); /* nothing to upload */
}
if(result)
size_t nread;
int l = sizeof(local_addr);
- if(getsockname(conn->data->firstsocket,
+ if(getsockname(conn->firstsocket,
(struct sockaddr *)LOCAL_ADDR, &l) < 0)
perror("getsockname()");
return AUTH_CONTINUE;
}
/*ret = command("ADAT %s", p)*/
- Curl_ftpsendf(conn->data->firstsocket, conn, "ADAT %s", p);
+ Curl_ftpsendf(conn->firstsocket, conn, "ADAT %s", p);
/* wait for feedback */
- nread = Curl_GetFTPResponse(conn->data->firstsocket,
+ nread = Curl_GetFTPResponse(conn->firstsocket,
conn->data->buffer, conn, NULL);
if(nread < 0)
return /*CURLE_OPERATION_TIMEOUTED*/-1;
save = set_command_prot(conn, prot_private);
/*ret = command("SITE KAUTH %s", name);***/
- Curl_ftpsendf(conn->data->firstsocket, conn,
+ Curl_ftpsendf(conn->firstsocket, conn,
"SITE KAUTH %s", conn->data->user);
/* wait for feedback */
- nread = Curl_GetFTPResponse(conn->data->firstsocket, conn->data->buffer,
+ nread = Curl_GetFTPResponse(conn->firstsocket, conn->data->buffer,
conn, NULL);
if(nread < 0)
return /*CURLE_OPERATION_TIMEOUTED*/;
}
memset (tktcopy.dat, 0, tktcopy.length);
/*ret = command("SITE KAUTH %s %s", name, p);***/
- Curl_ftpsendf(conn->data->firstsocket, conn,
+ Curl_ftpsendf(conn->firstsocket, conn,
"SITE KAUTH %s %s", name, p);
/* wait for feedback */
- nread = Curl_GetFTPResponse(conn->data->firstsocket, conn->data->buffer,
+ nread = Curl_GetFTPResponse(conn->firstsocket, conn->data->buffer,
conn, NULL);
if(nread < 0)
return /*CURLE_OPERATION_TIMEOUTED*/;
DYNA_GET_FUNCTION(int (*)(void *, char *, void *, void *, char **, char **, int (*)(void *, char *, int), void *, char *, int, unsigned long), ldap_entry2text);
DYNA_GET_FUNCTION(int (*)(void *, char *, void *, void *, char **, char **, int (*)(void *, char *, int), void *, char *, int, unsigned long, char *, char *), ldap_entry2html);
- server = ldap_open(data->hostname, data->port);
+ server = ldap_open(conn->hostname, conn->port);
if (server == NULL) {
failf(data, "LDAP: Cannot connect to %s:%d",
- data->hostname, data->port);
+ conn->hostname, conn->port);
status = CURLE_COULDNT_CONNECT;
} else {
rc = ldap_simple_bind_s(server, data->user, data->passwd);
}
if(level){
- Curl_ftpsendf(conn->data->firstsocket, conn,
+ Curl_ftpsendf(conn->firstsocket, conn,
"PBSZ %u", s);
/* wait for feedback */
- nread = Curl_GetFTPResponse(conn->data->firstsocket,
+ nread = Curl_GetFTPResponse(conn->firstsocket,
conn->data->buffer, conn, NULL);
if(nread < 0)
return /*CURLE_OPERATION_TIMEOUTED*/-1;
conn->buffer_size = s;
}
- Curl_ftpsendf(conn->data->firstsocket, conn,
+ Curl_ftpsendf(conn->firstsocket, conn,
"PROT %c", level["CSEP"]);
/* wait for feedback */
- nread = Curl_GetFTPResponse(conn->data->firstsocket,
+ nread = Curl_GetFTPResponse(conn->firstsocket,
conn->data->buffer, conn, NULL);
if(nread < 0)
return /*CURLE_OPERATION_TIMEOUTED*/-1;
}
infof(data, "Trying %s...\n", (*m)->name);
/*ret = command("AUTH %s", (*m)->name);***/
- Curl_ftpsendf(conn->data->firstsocket, conn,
+ Curl_ftpsendf(conn->firstsocket, conn,
"AUTH %s", (*m)->name);
/* wait for feedback */
- nread = Curl_GetFTPResponse(conn->data->firstsocket,
+ nread = Curl_GetFTPResponse(conn->firstsocket,
conn->data->buffer, conn, NULL);
if(nread < 0)
return /*CURLE_OPERATION_TIMEOUTED*/-1;
size_t *written)
{
size_t bytes_written;
- struct UrlData *data=conn->data; /* conn knows data, not vice versa */
#ifdef USE_SSLEAY
- if (data->ssl.use) {
+ if (conn->ssl.use) {
int loop=100; /* just a precaution to never loop endlessly */
while(loop--) {
- bytes_written = SSL_write(data->ssl.handle, mem, len);
+ bytes_written = SSL_write(conn->ssl.handle, mem, len);
if((-1 != bytes_written) ||
- (SSL_ERROR_WANT_WRITE != SSL_get_error(data->ssl.handle,
+ (SSL_ERROR_WANT_WRITE != SSL_get_error(conn->ssl.handle,
bytes_written) ))
break;
}
char *buf, size_t buffersize,
ssize_t *n)
{
- struct UrlData *data = conn->data;
ssize_t nread;
#ifdef USE_SSLEAY
- if (data->ssl.use) {
+ if (conn->ssl.use) {
int loop=100; /* just a precaution to never loop endlessly */
while(loop--) {
- nread = SSL_read(data->ssl.handle, buf, buffersize);
+ nread = SSL_read(conn->ssl.handle, buf, buffersize);
if((-1 != nread) ||
- (SSL_ERROR_WANT_READ != SSL_get_error(data->ssl.handle, nread) ))
+ (SSL_ERROR_WANT_READ != SSL_get_error(conn->ssl.handle, nread) ))
break;
}
}
static
int cert_stuff(struct UrlData *data,
+ struct connectdata *conn,
char *cert_file,
char *key_file)
{
*/
strcpy(global_passwd, data->cert_passwd);
/* Set passwd callback: */
- SSL_CTX_set_default_passwd_cb(data->ssl.ctx, passwd_callback);
+ SSL_CTX_set_default_passwd_cb(conn->ssl.ctx, passwd_callback);
}
- if (SSL_CTX_use_certificate_file(data->ssl.ctx,
+ if (SSL_CTX_use_certificate_file(conn->ssl.ctx,
cert_file,
SSL_FILETYPE_PEM) <= 0) {
failf(data, "unable to set certificate file (wrong password?)\n");
if (key_file == NULL)
key_file=cert_file;
- if (SSL_CTX_use_PrivateKey_file(data->ssl.ctx,
+ if (SSL_CTX_use_PrivateKey_file(conn->ssl.ctx,
key_file,
SSL_FILETYPE_PEM) <= 0) {
failf(data, "unable to set public key file\n");
return(0);
}
- ssl=SSL_new(data->ssl.ctx);
+ ssl=SSL_new(conn->ssl.ctx);
x509=SSL_get_certificate(ssl);
if (x509 != NULL)
/* Now we know that a key and cert have been set against
* the SSL context */
- if (!SSL_CTX_check_private_key(data->ssl.ctx)) {
+ if (!SSL_CTX_check_private_key(conn->ssl.ctx)) {
failf(data, "Private key does not match the certificate public key\n");
return(0);
}
/* ====================================================== */
int
-Curl_SSLConnect (struct UrlData *data)
+Curl_SSLConnect(struct connectdata *conn)
{
#ifdef USE_SSLEAY
- int err;
- char * str;
- SSL_METHOD *req_method;
+ struct UrlData *data = conn->data;
+ int err;
+ char * str;
+ SSL_METHOD *req_method;
- /* mark this is being ssl enabled from here on out. */
- data->ssl.use = TRUE;
+ /* mark this is being ssl enabled from here on out. */
+ conn->ssl.use = TRUE;
- /* Lets get nice error messages */
- SSL_load_error_strings();
+ /* Lets get nice error messages */
+ SSL_load_error_strings();
#ifdef HAVE_RAND_STATUS
- /* RAND_status() was introduced in OpenSSL 0.9.5 */
- if(0 == RAND_status())
+ /* RAND_status() was introduced in OpenSSL 0.9.5 */
+ if(0 == RAND_status())
#endif
{
/* We need to seed the PRNG properly! */
#endif
}
- /* Setup all the global SSL stuff */
- SSLeay_add_ssl_algorithms();
-
- switch(data->ssl.version) {
- default:
- req_method = SSLv23_client_method();
- break;
- case 2:
- req_method = SSLv2_client_method();
- break;
- case 3:
- req_method = SSLv3_client_method();
- break;
- }
+ /* Setup all the global SSL stuff */
+ SSLeay_add_ssl_algorithms();
+
+ switch(data->ssl.version) {
+ default:
+ req_method = SSLv23_client_method();
+ break;
+ case 2:
+ req_method = SSLv2_client_method();
+ break;
+ case 3:
+ req_method = SSLv3_client_method();
+ break;
+ }
- data->ssl.ctx = SSL_CTX_new(req_method);
+ conn->ssl.ctx = SSL_CTX_new(req_method);
- if(!data->ssl.ctx) {
- failf(data, "SSL: couldn't create a context!");
- return 1;
- }
+ if(!conn->ssl.ctx) {
+ failf(data, "SSL: couldn't create a context!");
+ return 1;
+ }
- if(data->cert) {
- if (!cert_stuff(data, data->cert, data->cert)) {
- failf(data, "couldn't use certificate!\n");
- return 2;
- }
+ if(data->cert) {
+ if (!cert_stuff(data, conn, data->cert, data->cert)) {
+ failf(data, "couldn't use certificate!\n");
+ return 2;
}
+ }
- if(data->ssl.verifypeer){
- SSL_CTX_set_verify(data->ssl.ctx,
- SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT|
- SSL_VERIFY_CLIENT_ONCE,
- cert_verify_callback);
- if (!SSL_CTX_load_verify_locations(data->ssl.ctx,
- data->ssl.CAfile,
- data->ssl.CApath)) {
- failf(data,"error setting cerficate verify locations\n");
- return 2;
- }
+ if(data->ssl.verifypeer){
+ SSL_CTX_set_verify(conn->ssl.ctx,
+ SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT|
+ SSL_VERIFY_CLIENT_ONCE,
+ cert_verify_callback);
+ if (!SSL_CTX_load_verify_locations(conn->ssl.ctx,
+ data->ssl.CAfile,
+ data->ssl.CApath)) {
+ failf(data,"error setting cerficate verify locations\n");
+ return 2;
}
- else
- SSL_CTX_set_verify(data->ssl.ctx, SSL_VERIFY_NONE, cert_verify_callback);
+ }
+ else
+ SSL_CTX_set_verify(conn->ssl.ctx, SSL_VERIFY_NONE, cert_verify_callback);
- /* Lets make an SSL structure */
- data->ssl.handle = SSL_new (data->ssl.ctx);
- SSL_set_connect_state (data->ssl.handle);
+ /* Lets make an SSL structure */
+ conn->ssl.handle = SSL_new (conn->ssl.ctx);
+ SSL_set_connect_state (conn->ssl.handle);
- data->ssl.server_cert = 0x0;
+ conn->ssl.server_cert = 0x0;
- /* pass the raw socket into the SSL layers */
- SSL_set_fd (data->ssl.handle, data->firstsocket);
- err = SSL_connect (data->ssl.handle);
+ /* pass the raw socket into the SSL layers */
+ SSL_set_fd (conn->ssl.handle, conn->firstsocket);
+ err = SSL_connect (conn->ssl.handle);
- if (-1 == err) {
- err = ERR_get_error();
- failf(data, "SSL: %s", ERR_error_string(err, NULL));
- return 10;
- }
+ if (-1 == err) {
+ err = ERR_get_error();
+ failf(data, "SSL: %s", ERR_error_string(err, NULL));
+ return 10;
+ }
- /* Informational message */
- infof (data, "SSL connection using %s\n",
- SSL_get_cipher(data->ssl.handle));
+ /* Informational message */
+ infof (data, "SSL connection using %s\n",
+ SSL_get_cipher(conn->ssl.handle));
- /* Get server's certificate (note: beware of dynamic allocation) - opt */
- /* major serious hack alert -- we should check certificates
- * to authenticate the server; otherwise we risk man-in-the-middle
- * attack
- */
-
- data->ssl.server_cert = SSL_get_peer_certificate (data->ssl.handle);
- if(!data->ssl.server_cert) {
- failf(data, "SSL: couldn't get peer certificate!");
- return 3;
- }
- infof (data, "Server certificate:\n");
+ /* Get server's certificate (note: beware of dynamic allocation) - opt */
+ /* major serious hack alert -- we should check certificates
+ * to authenticate the server; otherwise we risk man-in-the-middle
+ * attack
+ */
+
+ conn->ssl.server_cert = SSL_get_peer_certificate (conn->ssl.handle);
+ if(!conn->ssl.server_cert) {
+ failf(data, "SSL: couldn't get peer certificate!");
+ return 3;
+ }
+ infof (data, "Server certificate:\n");
- str = X509_NAME_oneline (X509_get_subject_name (data->ssl.server_cert),
- NULL, 0);
- if(!str) {
- failf(data, "SSL: couldn't get X509-subject!");
- return 4;
- }
- infof(data, "\t subject: %s\n", str);
- CRYPTO_free(str);
-
- str = X509_NAME_oneline (X509_get_issuer_name (data->ssl.server_cert),
- NULL, 0);
- if(!str) {
- failf(data, "SSL: couldn't get X509-issuer name!");
- return 5;
- }
- infof(data, "\t issuer: %s\n", str);
- CRYPTO_free(str);
+ str = X509_NAME_oneline (X509_get_subject_name (conn->ssl.server_cert),
+ NULL, 0);
+ if(!str) {
+ failf(data, "SSL: couldn't get X509-subject!");
+ return 4;
+ }
+ infof(data, "\t subject: %s\n", str);
+ CRYPTO_free(str);
+
+ str = X509_NAME_oneline (X509_get_issuer_name (conn->ssl.server_cert),
+ NULL, 0);
+ if(!str) {
+ failf(data, "SSL: couldn't get X509-issuer name!");
+ return 5;
+ }
+ infof(data, "\t issuer: %s\n", str);
+ CRYPTO_free(str);
- /* We could do all sorts of certificate verification stuff here before
- deallocating the certificate. */
+ /* We could do all sorts of certificate verification stuff here before
+ deallocating the certificate. */
- if(data->ssl.verifypeer) {
- data->ssl.certverifyresult=SSL_get_verify_result(data->ssl.handle);
- infof(data, "Verify result: %d\n", data->ssl.certverifyresult);
- }
- else
- data->ssl.certverifyresult=0;
+ if(data->ssl.verifypeer) {
+ data->ssl.certverifyresult=SSL_get_verify_result(conn->ssl.handle);
+ infof(data, "Verify result: %d\n", data->ssl.certverifyresult);
+ }
+ else
+ data->ssl.certverifyresult=0;
- X509_free(data->ssl.server_cert);
+ X509_free(conn->ssl.server_cert);
#else /* USE_SSLEAY */
- /* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */
- (void) data;
+ /* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */
+ (void) data;
#endif
- return 0;
+ return 0;
}
*
* $Id$
*****************************************************************************/
-int Curl_SSLConnect (struct UrlData *data);
+#include "urldata.h"
+int Curl_SSLConnect(struct connectdata *conn);
#endif
#define SB_LEN() (subend - subpointer)
static
-void telrcv(struct UrlData *data,
+void telrcv(struct connectdata *,
unsigned char *inbuf, /* Data received from socket */
int count); /* Number of bytes received */
const char *direction,
int cmd, int option);
-static void negotiate(struct UrlData *data);
-static void send_negotiation(struct UrlData *data, int cmd, int option);
-static void set_local_option(struct UrlData *data, int cmd, int option);
-static void set_remote_option(struct UrlData *data, int cmd, int option);
+static void negotiate(struct connectdata *);
+static void send_negotiation(struct connectdata *, int cmd, int option);
+static void set_local_option(struct connectdata *, int cmd, int option);
+static void set_remote_option(struct connectdata *, int cmd, int option);
static void printsub(struct UrlData *data,
int direction, unsigned char *pointer, int length);
-static void suboption(struct UrlData *data);
+static void suboption(struct connectdata *);
/* suboptions */
static char subbuffer[SUBBUFSIZE];
#define EMPTY 0
#define OPPOSITE 1
+static int please_negotiate = 0;
+static int already_negotiated = 0;
static int us[256];
static int usq[256];
static int us_preferred[256];
static int himq[256];
static int him_preferred[256];
+static char *subopt_ttype = NULL; /* Set with suboption TTYPE */
+static char *subopt_xdisploc = NULL; /* Set with suboption XDISPLOC */
+static struct curl_slist *telnet_vars = NULL; /* Environment variables */
+
static
-void init_telnet(struct UrlData *data)
+void init_telnet(struct connectdata *conn)
{
- telrcv_state = TS_DATA;
-
- /* Init suboptions */
- SB_CLEAR();
-
- /* Set all options to NO */
- memset(us, NO, 256);
- memset(usq, NO, 256);
- memset(us_preferred, NO, 256);
- memset(him, NO, 256);
- memset(himq, NO, 256);
- memset(him_preferred, NO, 256);
-
- /* Set the options we want */
- us_preferred[TELOPT_BINARY] = YES;
- us_preferred[TELOPT_SGA] = YES;
- him_preferred[TELOPT_BINARY] = YES;
- him_preferred[TELOPT_SGA] = YES;
-
- /* Start negotiating */
- negotiate(data);
+ telrcv_state = TS_DATA;
+
+ /* Init suboptions */
+ SB_CLEAR();
+
+ /* Set all options to NO */
+ memset(us, NO, 256);
+ memset(usq, NO, 256);
+ memset(us_preferred, NO, 256);
+ memset(him, NO, 256);
+ memset(himq, NO, 256);
+ memset(him_preferred, NO, 256);
+
+ /* Set the options we want by default */
+ us_preferred[TELOPT_BINARY] = YES;
+ us_preferred[TELOPT_SGA] = YES;
+ him_preferred[TELOPT_BINARY] = YES;
+ him_preferred[TELOPT_SGA] = YES;
}
-static void negotiate(struct UrlData *data)
+static void negotiate(struct connectdata *conn)
{
- int i;
+ int i;
- for(i = 0;i < NTELOPTS;i++)
- {
- if(us_preferred[i] == YES)
- set_local_option(data, i, YES);
+ for(i = 0;i < NTELOPTS;i++)
+ {
+ if(us_preferred[i] == YES)
+ set_local_option(conn, i, YES);
- if(him_preferred[i] == YES)
- set_remote_option(data, i, YES);
- }
+ if(him_preferred[i] == YES)
+ set_remote_option(conn, i, YES);
+ }
}
static void printoption(struct UrlData *data,
const char *direction, int cmd, int option)
{
- char *fmt;
- char *opt;
+ char *fmt;
+ char *opt;
- if (data->bits.verbose)
- {
- if (cmd == IAC)
- {
- if (TELCMD_OK(option))
- printf("%s IAC %s\n", direction, TELCMD(option));
- else
- printf("%s IAC %d\n", direction, option);
- }
+ if (data->bits.verbose)
+ {
+ if (cmd == IAC)
+ {
+ if (TELCMD_OK(option))
+ printf("%s IAC %s\n", direction, TELCMD(option));
else
+ printf("%s IAC %d\n", direction, option);
+ }
+ else
+ {
+ fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" :
+ (cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0;
+ if (fmt)
{
- fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" :
- (cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0;
- if (fmt)
- {
- if (TELOPT_OK(option))
- opt = TELOPT(option);
- else if (option == TELOPT_EXOPL)
- opt = "EXOPL";
- else
- opt = NULL;
-
- if(opt)
- printf("%s %s %s\n", direction, fmt, opt);
- else
- printf("%s %s %d\n", direction, fmt, option);
- }
- else
- printf("%s %d %d\n", direction, cmd, option);
+ if (TELOPT_OK(option))
+ opt = TELOPT(option);
+ else if (option == TELOPT_EXOPL)
+ opt = "EXOPL";
+ else
+ opt = NULL;
+
+ if(opt)
+ printf("%s %s %s\n", direction, fmt, opt);
+ else
+ printf("%s %s %d\n", direction, fmt, option);
}
- }
+ else
+ printf("%s %d %d\n", direction, cmd, option);
+ }
+ }
}
-static void send_negotiation(struct UrlData *data, int cmd, int option)
+static void send_negotiation(struct connectdata *conn, int cmd, int option)
{
unsigned char buf[3];
buf[1] = cmd;
buf[2] = option;
- swrite(data->firstsocket, buf, 3);
+ swrite(conn->firstsocket, buf, 3);
- printoption(data, "SENT", cmd, option);
+ printoption(conn->data, "SENT", cmd, option);
}
static
-void set_remote_option(struct UrlData *data, int option, int newstate)
+void set_remote_option(struct connectdata *conn, int option, int newstate)
{
- if(newstate == YES)
- {
- switch(him[option])
- {
+ if(newstate == YES)
+ {
+ switch(him[option])
+ {
case NO:
- him[option] = WANTYES;
- send_negotiation(data, DO, option);
- break;
+ him[option] = WANTYES;
+ send_negotiation(conn, DO, option);
+ break;
case YES:
- /* Already enabled */
- break;
+ /* Already enabled */
+ break;
case WANTNO:
- switch(himq[option])
- {
- case EMPTY:
- /* Already negotiating for YES, queue the request */
- himq[option] = OPPOSITE;
- break;
- case OPPOSITE:
- /* Error: already queued an enable request */
- break;
- }
- break;
+ switch(himq[option])
+ {
+ case EMPTY:
+ /* Already negotiating for YES, queue the request */
+ himq[option] = OPPOSITE;
+ break;
+ case OPPOSITE:
+ /* Error: already queued an enable request */
+ break;
+ }
+ break;
case WANTYES:
- switch(himq[option])
- {
- case EMPTY:
- /* Error: already negotiating for enable */
- break;
- case OPPOSITE:
- himq[option] = EMPTY;
- break;
- }
- break;
- }
- }
- else /* NO */
- {
- switch(him[option])
- {
+ switch(himq[option])
+ {
+ case EMPTY:
+ /* Error: already negotiating for enable */
+ break;
+ case OPPOSITE:
+ himq[option] = EMPTY;
+ break;
+ }
+ break;
+ }
+ }
+ else /* NO */
+ {
+ switch(him[option])
+ {
case NO:
- /* Already disabled */
- break;
+ /* Already disabled */
+ break;
case YES:
- him[option] = WANTNO;
- send_negotiation(data, DONT, option);
- break;
+ him[option] = WANTNO;
+ send_negotiation(conn, DONT, option);
+ break;
case WANTNO:
- switch(himq[option])
- {
- case EMPTY:
- /* Already negotiating for NO */
- break;
- case OPPOSITE:
- himq[option] = EMPTY;
- break;
- }
- break;
+ switch(himq[option])
+ {
+ case EMPTY:
+ /* Already negotiating for NO */
+ break;
+ case OPPOSITE:
+ himq[option] = EMPTY;
+ break;
+ }
+ break;
case WANTYES:
- switch(himq[option])
- {
- case EMPTY:
- himq[option] = OPPOSITE;
- break;
- case OPPOSITE:
- break;
- }
- break;
- }
- }
+ switch(himq[option])
+ {
+ case EMPTY:
+ himq[option] = OPPOSITE;
+ break;
+ case OPPOSITE:
+ break;
+ }
+ break;
+ }
+ }
}
static
-void rec_will(struct UrlData *data, int option)
+void rec_will(struct connectdata *conn, int option)
{
- switch(him[option])
- {
- case NO:
+ switch(him[option])
+ {
+ case NO:
if(him_preferred[option] == YES)
{
- him[option] = YES;
- send_negotiation(data, DO, option);
+ him[option] = YES;
+ send_negotiation(conn, DO, option);
}
else
{
- send_negotiation(data, DONT, option);
+ send_negotiation(conn, DONT, option);
}
break;
- case YES:
+ case YES:
/* Already enabled */
break;
- case WANTNO:
+ case WANTNO:
switch(himq[option])
{
- case EMPTY:
- /* Error: DONT answered by WILL */
- him[option] = NO;
- break;
- case OPPOSITE:
- /* Error: DONT answered by WILL */
- him[option] = YES;
- himq[option] = EMPTY;
- break;
+ case EMPTY:
+ /* Error: DONT answered by WILL */
+ him[option] = NO;
+ break;
+ case OPPOSITE:
+ /* Error: DONT answered by WILL */
+ him[option] = YES;
+ himq[option] = EMPTY;
+ break;
}
break;
- case WANTYES:
+ case WANTYES:
switch(himq[option])
{
- case EMPTY:
- him[option] = YES;
- break;
- case OPPOSITE:
- him[option] = WANTNO;
- himq[option] = EMPTY;
- send_negotiation(data, DONT, option);
- break;
+ case EMPTY:
+ him[option] = YES;
+ break;
+ case OPPOSITE:
+ him[option] = WANTNO;
+ himq[option] = EMPTY;
+ send_negotiation(conn, DONT, option);
+ break;
}
break;
- }
+ }
}
static
-void rec_wont(struct UrlData *data, int option)
+void rec_wont(struct connectdata *conn, int option)
{
- switch(him[option])
- {
- case NO:
+ switch(him[option])
+ {
+ case NO:
/* Already disabled */
break;
- case YES:
+ case YES:
him[option] = NO;
- send_negotiation(data, DONT, option);
+ send_negotiation(conn, DONT, option);
break;
- case WANTNO:
+ case WANTNO:
switch(himq[option])
{
- case EMPTY:
- him[option] = NO;
- break;
+ case EMPTY:
+ him[option] = NO;
+ break;
- case OPPOSITE:
- him[option] = WANTYES;
- himq[option] = EMPTY;
- send_negotiation(data, DO, option);
- break;
+ case OPPOSITE:
+ him[option] = WANTYES;
+ himq[option] = EMPTY;
+ send_negotiation(conn, DO, option);
+ break;
}
break;
- case WANTYES:
+ case WANTYES:
switch(himq[option])
{
- case EMPTY:
- him[option] = NO;
- break;
- case OPPOSITE:
- him[option] = NO;
- himq[option] = EMPTY;
- break;
+ case EMPTY:
+ him[option] = NO;
+ break;
+ case OPPOSITE:
+ him[option] = NO;
+ himq[option] = EMPTY;
+ break;
}
break;
- }
+ }
}
-void set_local_option(struct UrlData *data, int option, int newstate)
+void set_local_option(struct connectdata *conn, int option, int newstate)
{
- if(newstate == YES)
- {
- switch(us[option])
- {
+ if(newstate == YES)
+ {
+ switch(us[option])
+ {
case NO:
- us[option] = WANTYES;
- send_negotiation(data, WILL, option);
- break;
+ us[option] = WANTYES;
+ send_negotiation(conn, WILL, option);
+ break;
case YES:
- /* Already enabled */
- break;
+ /* Already enabled */
+ break;
case WANTNO:
- switch(usq[option])
- {
- case EMPTY:
- /* Already negotiating for YES, queue the request */
- usq[option] = OPPOSITE;
- break;
- case OPPOSITE:
- /* Error: already queued an enable request */
- break;
- }
- break;
+ switch(usq[option])
+ {
+ case EMPTY:
+ /* Already negotiating for YES, queue the request */
+ usq[option] = OPPOSITE;
+ break;
+ case OPPOSITE:
+ /* Error: already queued an enable request */
+ break;
+ }
+ break;
case WANTYES:
- switch(usq[option])
- {
- case EMPTY:
- /* Error: already negotiating for enable */
- break;
- case OPPOSITE:
- usq[option] = EMPTY;
- break;
- }
- break;
- }
- }
- else /* NO */
- {
- switch(us[option])
- {
+ switch(usq[option])
+ {
+ case EMPTY:
+ /* Error: already negotiating for enable */
+ break;
+ case OPPOSITE:
+ usq[option] = EMPTY;
+ break;
+ }
+ break;
+ }
+ }
+ else /* NO */
+ {
+ switch(us[option])
+ {
case NO:
- /* Already disabled */
- break;
+ /* Already disabled */
+ break;
case YES:
- us[option] = WANTNO;
- send_negotiation(data, WONT, option);
- break;
+ us[option] = WANTNO;
+ send_negotiation(conn, WONT, option);
+ break;
case WANTNO:
- switch(usq[option])
- {
- case EMPTY:
- /* Already negotiating for NO */
- break;
- case OPPOSITE:
- usq[option] = EMPTY;
- break;
- }
- break;
+ switch(usq[option])
+ {
+ case EMPTY:
+ /* Already negotiating for NO */
+ break;
+ case OPPOSITE:
+ usq[option] = EMPTY;
+ break;
+ }
+ break;
case WANTYES:
- switch(usq[option])
- {
- case EMPTY:
- usq[option] = OPPOSITE;
- break;
- case OPPOSITE:
- break;
- }
- break;
- }
- }
+ switch(usq[option])
+ {
+ case EMPTY:
+ usq[option] = OPPOSITE;
+ break;
+ case OPPOSITE:
+ break;
+ }
+ break;
+ }
+ }
}
static
-void rec_do(struct UrlData *data, int option)
+void rec_do(struct connectdata *conn, int option)
{
- switch(us[option])
- {
- case NO:
+ switch(us[option])
+ {
+ case NO:
if(us_preferred[option] == YES)
{
- us[option] = YES;
- send_negotiation(data, WILL, option);
+ us[option] = YES;
+ send_negotiation(conn, WILL, option);
}
else
{
- send_negotiation(data, WONT, option);
+ send_negotiation(conn, WONT, option);
}
break;
- case YES:
+ case YES:
/* Already enabled */
break;
- case WANTNO:
+ case WANTNO:
switch(usq[option])
{
- case EMPTY:
- /* Error: DONT answered by WILL */
- us[option] = NO;
- break;
- case OPPOSITE:
- /* Error: DONT answered by WILL */
- us[option] = YES;
- usq[option] = EMPTY;
- break;
+ case EMPTY:
+ /* Error: DONT answered by WILL */
+ us[option] = NO;
+ break;
+ case OPPOSITE:
+ /* Error: DONT answered by WILL */
+ us[option] = YES;
+ usq[option] = EMPTY;
+ break;
}
break;
- case WANTYES:
+ case WANTYES:
switch(usq[option])
{
- case EMPTY:
- us[option] = YES;
- break;
- case OPPOSITE:
- us[option] = WANTNO;
- himq[option] = EMPTY;
- send_negotiation(data, WONT, option);
- break;
+ case EMPTY:
+ us[option] = YES;
+ break;
+ case OPPOSITE:
+ us[option] = WANTNO;
+ himq[option] = EMPTY;
+ send_negotiation(conn, WONT, option);
+ break;
}
break;
- }
+ }
}
static
-void rec_dont(struct UrlData *data, int option)
+void rec_dont(struct connectdata *conn, int option)
{
- switch(us[option])
- {
- case NO:
+ switch(us[option])
+ {
+ case NO:
/* Already disabled */
break;
- case YES:
+ case YES:
us[option] = NO;
- send_negotiation(data, WONT, option);
+ send_negotiation(conn, WONT, option);
break;
- case WANTNO:
+ case WANTNO:
switch(usq[option])
{
- case EMPTY:
- us[option] = NO;
- break;
+ case EMPTY:
+ us[option] = NO;
+ break;
- case OPPOSITE:
- us[option] = WANTYES;
- usq[option] = EMPTY;
- send_negotiation(data, WILL, option);
- break;
+ case OPPOSITE:
+ us[option] = WANTYES;
+ usq[option] = EMPTY;
+ send_negotiation(conn, WILL, option);
+ break;
}
break;
- case WANTYES:
+ case WANTYES:
switch(usq[option])
{
- case EMPTY:
- us[option] = NO;
- break;
- case OPPOSITE:
- us[option] = NO;
- usq[option] = EMPTY;
- break;
+ case EMPTY:
+ us[option] = NO;
+ break;
+ case OPPOSITE:
+ us[option] = NO;
+ usq[option] = EMPTY;
+ break;
}
break;
- }
+ }
}
int direction, /* '<' or '>' */
unsigned char *pointer, /* where suboption data is */
int length) /* length of suboption data */
-
{
- int i = 0;
-
- if (data->bits.verbose)
- {
- if (direction)
+ int i = 0;
+
+ if (data->bits.verbose)
+ {
+ if (direction)
+ {
+ printf("%s IAC SB ", (direction == '<')? "RCVD":"SENT");
+ if (length >= 3)
{
- printf("%s IAC SB ", (direction == '<')? "RCVD":"SENT");
- if (length >= 3)
- {
- int j;
-
- i = pointer[length-2];
- j = pointer[length-1];
-
- if (i != IAC || j != SE)
- {
- printf("(terminated by ");
- if (TELOPT_OK(i))
- printf("%s ", TELOPT(i));
- else if (TELCMD_OK(i))
- printf("%s ", TELCMD(i));
- else
- printf("%d ", i);
- if (TELOPT_OK(j))
- printf("%s", TELOPT(j));
- else if (TELCMD_OK(j))
- printf("%s", TELCMD(j));
- else
- printf("%d", j);
- printf(", not IAC SE!) ");
+ int j;
+
+ i = pointer[length-2];
+ j = pointer[length-1];
+
+ if (i != IAC || j != SE)
+ {
+ printf("(terminated by ");
+ if (TELOPT_OK(i))
+ printf("%s ", TELOPT(i));
+ else if (TELCMD_OK(i))
+ printf("%s ", TELCMD(i));
+ else
+ printf("%d ", i);
+ if (TELOPT_OK(j))
+ printf("%s", TELOPT(j));
+ else if (TELCMD_OK(j))
+ printf("%s", TELCMD(j));
+ else
+ printf("%d", j);
+ printf(", not IAC SE!) ");
+ }
+ }
+ length -= 2;
+ }
+ if (length < 1)
+ {
+ printf("(Empty suboption?)");
+ return;
+ }
+
+ if (TELOPT_OK(pointer[0])) {
+ switch(pointer[0]) {
+ case TELOPT_TTYPE:
+ case TELOPT_XDISPLOC:
+ case TELOPT_NEW_ENVIRON:
+ printf("%s", TELOPT(pointer[0]));
+ break;
+ default:
+ printf("%s (unsupported)", TELOPT(pointer[0]));
+ break;
+ }
+ }
+ else
+ printf("%d (unknown)", pointer[i]);
+
+ switch(pointer[1]) {
+ case TELQUAL_IS:
+ printf(" IS");
+ break;
+ case TELQUAL_SEND:
+ printf(" SEND");
+ break;
+ case TELQUAL_INFO:
+ printf(" INFO/REPLY");
+ break;
+ case TELQUAL_NAME:
+ printf(" NAME");
+ break;
+ }
+
+ switch(pointer[0]) {
+ case TELOPT_TTYPE:
+ case TELOPT_XDISPLOC:
+ pointer[length] = 0;
+ printf(" \"%s\"", &pointer[2]);
+ break;
+ case TELOPT_NEW_ENVIRON:
+ if(pointer[1] == TELQUAL_IS) {
+ printf(" ");
+ for(i = 3;i < length;i++) {
+ switch(pointer[i]) {
+ case NEW_ENV_VAR:
+ printf(", ");
+ break;
+ case NEW_ENV_VALUE:
+ printf(" = ");
+ break;
+ default:
+ printf("%c", pointer[i]);
+ break;
}
- }
- length -= 2;
+ }
+ }
+ break;
+ default:
+ for (i = 2; i < length; i++)
+ printf(" %.2x", pointer[i]);
+ break;
+ }
+
+ if (direction)
+ {
+ printf("\n");
+ }
+ }
+}
+
+static int check_telnet_options(struct connectdata *conn)
+{
+ struct curl_slist *head;
+ char option_keyword[128];
+ char option_arg[256];
+ char *buf;
+ struct UrlData *data = conn->data;
+
+ /* Add the user name as an environment variable if it
+ was given on the command line */
+ if(data->bits.user_passwd)
+ {
+ char *buf = malloc(256);
+ sprintf(buf, "USER,%s", data->user);
+ telnet_vars = curl_slist_append(telnet_vars, buf);
+
+ us_preferred[TELOPT_NEW_ENVIRON] = YES;
+ }
+
+ for(head = data->telnet_options; head; head=head->next) {
+ if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
+ option_keyword, option_arg) == 2) {
+
+ /* Terminal type */
+ if(strequal(option_keyword, "TTYPE")) {
+ subopt_ttype = option_arg;
+ us_preferred[TELOPT_TTYPE] = YES;
+ continue;
}
- if (length < 1)
- {
- printf("(Empty suboption?)");
- return;
+
+ /* Display variable */
+ if(strequal(option_keyword, "XDISPLOC")) {
+ subopt_xdisploc = option_arg;
+ us_preferred[TELOPT_XDISPLOC] = YES;
+ continue;
}
- if (TELOPT_OK(pointer[0]))
- printf("%s (unknown)", TELOPT(pointer[0]));
- else
- printf("%d (unknown)", pointer[i]);
- for (i = 1; i < length; i++)
- printf(" %d", pointer[i]);
-
- if (direction)
- {
- printf("\n");
+ /* Environment variable */
+ if(strequal(option_keyword, "NEW_ENV")) {
+ buf = strdup(option_arg);
+ if(!buf)
+ return CURLE_OUT_OF_MEMORY;
+ telnet_vars = curl_slist_append(telnet_vars, buf);
+ us_preferred[TELOPT_NEW_ENVIRON] = YES;
+ continue;
}
- }
+
+ failf(data, "Unknown telnet option %s", head->data);
+ return CURLE_UNKNOWN_TELNET_OPTION;
+ } else {
+ failf(data, "Syntax error in telnet option: %s", head->data);
+ return CURLE_TELNET_OPTION_SYNTAX;
+ }
+ }
+
+ return CURLE_OK;
}
/*
* No suboptions are supported yet.
*/
-static void suboption(struct UrlData *data)
+static void suboption(struct connectdata *conn)
{
- printsub(data, '<', (unsigned char *)subbuffer, SB_LEN()+2);
- return;
+ struct curl_slist *v;
+ unsigned char subchar;
+ unsigned char temp[2048];
+ int len;
+ int tmplen;
+ char varname[128];
+ char varval[128];
+ struct UrlData *data = conn->data;
+
+ printsub(data, '<', (unsigned char *)subbuffer, SB_LEN()+2);
+ switch (subchar = SB_GET()) {
+ case TELOPT_TTYPE:
+ len = strlen(subopt_ttype) + 4 + 2;
+ snprintf((char *)temp, sizeof(temp),
+ "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
+ TELQUAL_IS, subopt_ttype, IAC, SE);
+ swrite(conn->firstsocket, temp, len);
+ printsub(data, '>', &temp[2], len-2);
+ break;
+ case TELOPT_XDISPLOC:
+ len = strlen(subopt_xdisploc) + 4 + 2;
+ snprintf((char *)temp, sizeof(temp),
+ "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
+ TELQUAL_IS, subopt_xdisploc, IAC, SE);
+ swrite(conn->firstsocket, temp, len);
+ printsub(data, '>', &temp[2], len-2);
+ break;
+ case TELOPT_NEW_ENVIRON:
+ snprintf((char *)temp, sizeof(temp),
+ "%c%c%c%c", IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_IS);
+ len = 4;
+
+ for(v = telnet_vars;v;v = v->next) {
+ tmplen = (strlen(v->data) + 1);
+ /* Add the variable only if it fits */
+ if(len + tmplen < sizeof(temp)-6) {
+ sscanf(v->data, "%127[^,],%s", varname, varval);
+ snprintf((char *)&temp[len], sizeof(temp) - len,
+ "%c%s%c%s", NEW_ENV_VAR, varname,
+ NEW_ENV_VALUE, varval);
+ len += tmplen;
+ }
+ }
+ snprintf((char *)&temp[len], sizeof(temp) - len,
+ "%c%c", IAC, SE);
+ len += 2;
+ swrite(conn->firstsocket, temp, len);
+ printsub(data, '>', &temp[2], len-2);
+ break;
+ }
+ return;
}
static
-void telrcv(struct UrlData *data,
- unsigned char *inbuf, /* Data received from socket */
- int count) /* Number of bytes received */
+void telrcv(struct connectdata *conn,
+ unsigned char *inbuf, /* Data received from socket */
+ int count) /* Number of bytes received */
{
- unsigned char c;
- int index = 0;
+ unsigned char c;
+ int index = 0;
+ struct UrlData *data = conn->data;
- while(count--)
- {
- c = inbuf[index++];
+ while(count--)
+ {
+ c = inbuf[index++];
- switch (telrcv_state)
- {
+ switch (telrcv_state)
+ {
case TS_CR:
- telrcv_state = TS_DATA;
- if (c == '\0')
- {
- break; /* Ignore \0 after CR */
- }
+ telrcv_state = TS_DATA;
+ if (c == '\0')
+ {
+ break; /* Ignore \0 after CR */
+ }
- Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1);
- continue;
+ Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1);
+ continue;
case TS_DATA:
- if (c == IAC)
- {
- telrcv_state = TS_IAC;
- break;
- }
- else if(c == '\r')
- {
- telrcv_state = TS_CR;
- }
-
- Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1);
- continue;
+ if (c == IAC)
+ {
+ telrcv_state = TS_IAC;
+ break;
+ }
+ else if(c == '\r')
+ {
+ telrcv_state = TS_CR;
+ }
+
+ Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1);
+ continue;
case TS_IAC:
- process_iac:
- switch (c)
- {
- case WILL:
- telrcv_state = TS_WILL;
- continue;
- case WONT:
- telrcv_state = TS_WONT;
- continue;
- case DO:
- telrcv_state = TS_DO;
- continue;
- case DONT:
- telrcv_state = TS_DONT;
- continue;
- case SB:
- SB_CLEAR();
- telrcv_state = TS_SB;
- continue;
- case IAC:
+ process_iac:
+ switch (c)
+ {
+ case WILL:
+ telrcv_state = TS_WILL;
+ continue;
+ case WONT:
+ telrcv_state = TS_WONT;
+ continue;
+ case DO:
+ telrcv_state = TS_DO;
+ continue;
+ case DONT:
+ telrcv_state = TS_DONT;
+ continue;
+ case SB:
+ SB_CLEAR();
+ telrcv_state = TS_SB;
+ continue;
+ case IAC:
Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1);
break;
- case DM:
- case NOP:
- case GA:
- default:
- printoption(data, "RCVD", IAC, c);
- break;
- }
- telrcv_state = TS_DATA;
- continue;
+ case DM:
+ case NOP:
+ case GA:
+ default:
+ printoption(data, "RCVD", IAC, c);
+ break;
+ }
+ telrcv_state = TS_DATA;
+ continue;
case TS_WILL:
- printoption(data, "RCVD", WILL, c);
- rec_will(data, c);
- telrcv_state = TS_DATA;
- continue;
+ printoption(data, "RCVD", WILL, c);
+ please_negotiate = 1;
+ rec_will(conn, c);
+ telrcv_state = TS_DATA;
+ continue;
case TS_WONT:
- printoption(data, "RCVD", WONT, c);
- rec_wont(data, c);
- telrcv_state = TS_DATA;
- continue;
+ printoption(data, "RCVD", WONT, c);
+ please_negotiate = 1;
+ rec_wont(conn, c);
+ telrcv_state = TS_DATA;
+ continue;
case TS_DO:
- printoption(data, "RCVD", DO, c);
- rec_do(data, c);
- telrcv_state = TS_DATA;
- continue;
+ printoption(data, "RCVD", DO, c);
+ please_negotiate = 1;
+ rec_do(conn, c);
+ telrcv_state = TS_DATA;
+ continue;
case TS_DONT:
- printoption(data, "RCVD", DONT, c);
- rec_dont(data, c);
- telrcv_state = TS_DATA;
- continue;
+ printoption(data, "RCVD", DONT, c);
+ please_negotiate = 1;
+ rec_dont(conn, c);
+ telrcv_state = TS_DATA;
+ continue;
case TS_SB:
- if (c == IAC)
- {
- telrcv_state = TS_SE;
- }
- else
- {
- SB_ACCUM(c);
- }
- continue;
+ if (c == IAC)
+ {
+ telrcv_state = TS_SE;
+ }
+ else
+ {
+ SB_ACCUM(c);
+ }
+ continue;
case TS_SE:
- if (c != SE)
- {
- if (c != IAC)
- {
- /*
- * This is an error. We only expect to get
- * "IAC IAC" or "IAC SE". Several things may
- * have happend. An IAC was not doubled, the
- * IAC SE was left off, or another option got
- * inserted into the suboption are all possibilities.
- * If we assume that the IAC was not doubled,
- * and really the IAC SE was left off, we could
- * get into an infinate loop here. So, instead,
- * we terminate the suboption, and process the
- * partial suboption if we can.
- */
- SB_ACCUM((unsigned char)IAC);
- SB_ACCUM(c);
- subpointer -= 2;
- SB_TERM();
+ if (c != SE)
+ {
+ if (c != IAC)
+ {
+ /*
+ * This is an error. We only expect to get
+ * "IAC IAC" or "IAC SE". Several things may
+ * have happend. An IAC was not doubled, the
+ * IAC SE was left off, or another option got
+ * inserted into the suboption are all possibilities.
+ * If we assume that the IAC was not doubled,
+ * and really the IAC SE was left off, we could
+ * get into an infinate loop here. So, instead,
+ * we terminate the suboption, and process the
+ * partial suboption if we can.
+ */
+ SB_ACCUM((unsigned char)IAC);
+ SB_ACCUM(c);
+ subpointer -= 2;
+ SB_TERM();
- printoption(data, "In SUBOPTION processing, RCVD", IAC, c);
- suboption(data); /* handle sub-option */
- telrcv_state = TS_IAC;
- goto process_iac;
- }
- SB_ACCUM(c);
- telrcv_state = TS_SB;
- }
- else
- {
- SB_ACCUM((unsigned char)IAC);
- SB_ACCUM((unsigned char)SE);
- subpointer -= 2;
- SB_TERM();
- suboption(data); /* handle sub-option */
- telrcv_state = TS_DATA;
- }
- break;
- }
- }
+ printoption(data, "In SUBOPTION processing, RCVD", IAC, c);
+ suboption(conn); /* handle sub-option */
+ telrcv_state = TS_IAC;
+ goto process_iac;
+ }
+ SB_ACCUM(c);
+ telrcv_state = TS_SB;
+ }
+ else
+ {
+ SB_ACCUM((unsigned char)IAC);
+ SB_ACCUM((unsigned char)SE);
+ subpointer -= 2;
+ SB_TERM();
+ suboption(conn); /* handle sub-option */
+ telrcv_state = TS_DATA;
+ }
+ break;
+ }
+ }
}
CURLcode Curl_telnet_done(struct connectdata *conn)
{
+ curl_slist_free_all(telnet_vars);
return CURLE_OK;
}
CURLcode Curl_telnet(struct connectdata *conn)
{
+ CURLcode code;
struct UrlData *data = conn->data;
- int sockfd = data->firstsocket;
+ int sockfd = conn->firstsocket;
fd_set readfd;
fd_set keepfd;
char *buf = data->buffer;
ssize_t nread;
- init_telnet(data);
+ init_telnet(conn);
+ code = check_telnet_options(conn);
+ if(code)
+ return code;
+
FD_ZERO (&readfd); /* clear it */
FD_SET (sockfd, &readfd);
FD_SET (1, &readfd);
if(outbuf[0] == IAC)
outbuf[out_count++] = IAC;
- Curl_write(conn, data->firstsocket, outbuf,
+ Curl_write(conn, conn->firstsocket, outbuf,
out_count, &bytes_written);
}
}
break;
}
- telrcv(data, (unsigned char *)buf, nread);
+ telrcv(conn, (unsigned char *)buf, nread);
+
+ /* Negotiate if the peer has started negotiating,
+ otherwise don't. We don't want to speak telnet with
+ non-telnet servers, like POP or SMTP. */
+ if(please_negotiate && !already_negotiated) {
+ negotiate(conn);
+ already_negotiated = 1;
+ }
}
}
}
/* mark this as "no further transfer wanted" */
return Curl_Transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
}
-
-
if (strnequal("Content-Length", p, 14) &&
sscanf (p+14, ": %ld", &contentlength))
conn->size = contentlength;
+ else if (strnequal("Connection: close", p,
+ strlen("Connection: close"))) {
+ /*
+ * [RFC 2616, section 8.1.2.1]
+ * "Connection: close" is HTTP/1.1 language and means that
+ * the connection will close when this request has been
+ * served.
+ */
+ conn->bits.close = TRUE; /* close when done */
+ }
else if (strnequal("Content-Range", p, 13)) {
if (sscanf (p+13, ": bytes %d-", &offset) ||
sscanf (p+13, ": bytes: %d-", &offset)) {
if (data->maxredirs && (data->followlocation >= data->maxredirs)) {
failf(data,"Maximum (%d) redirects followed", data->maxredirs);
+#ifdef USE_OLD_DISCONNECT
curl_disconnect(c_connect);
+#endif
res=CURLE_TOO_MANY_REDIRECTS;
break;
}
*/
break;
}
+#ifdef USE_OLD_DISCONNECT
curl_disconnect(c_connect);
+#endif
continue;
}
+#ifdef USE_OLD_DISCONNECT
curl_disconnect(c_connect);
+#endif
}
break; /* it only reaches here when this shouldn't loop */
#include "memdebug.h"
#endif
-/* -- -- */
+/* Local static prototypes */
+static int ConnectionKillOne(struct UrlData *data);
+static bool ConnectionExists(struct UrlData *data,
+ struct connectdata *needle,
+ struct connectdata **usethis);
+static unsigned int ConnectionStore(struct UrlData *data,
+ struct connectdata *conn);
-CURLcode _urlget(struct UrlData *data);
-
/* does nothing, returns OK */
CURLcode curl_init(void)
{
{
}
-void static urlfree(struct UrlData *data, bool totally)
+CURLcode curl_close(CURL *curl)
{
-#ifdef USE_SSLEAY
- if (data->ssl.use) {
- if(data->ssl.handle) {
- (void)SSL_shutdown(data->ssl.handle);
- SSL_set_connect_state(data->ssl.handle);
-
- SSL_free (data->ssl.handle);
- data->ssl.handle = NULL;
- }
- if(data->ssl.ctx) {
- SSL_CTX_free (data->ssl.ctx);
- data->ssl.ctx = NULL;
- }
- data->ssl.use = FALSE; /* get back to ordinary socket usage */
- }
-#endif /* USE_SSLEAY */
-
- /* close possibly still open sockets */
- if(-1 != data->secondarysocket) {
- sclose(data->secondarysocket);
- data->secondarysocket = -1;
- }
- if(-1 != data->firstsocket) {
- sclose(data->firstsocket);
- data->firstsocket=-1;
- }
+ struct UrlData *data=(struct UrlData *)curl;
+
+ /* Loop through all open connections and kill them one by one */
+ while(-1 != ConnectionKillOne(data));
if(data->bits.proxystringalloc) {
data->bits.proxystringalloc=FALSE;;
switch off that knowledge again... */
data->bits.httpproxy=FALSE;
}
-
+
+
if(data->bits.rangestringalloc) {
free(data->range);
data->range=NULL;
data->ptr_host=NULL;
}
- if(totally) {
- /* we let the switch decide whether we're doing a part or total
- cleanup */
-
- /* check for allocated [URL] memory to free: */
- if(data->freethis)
- free(data->freethis);
-
- if(data->headerbuff)
- free(data->headerbuff);
+ /* check for allocated [URL] memory to free: */
+ if(data->freethis)
+ free(data->freethis);
- if(data->free_referer)
- free(data->referer);
+ if(data->headerbuff)
+ free(data->headerbuff);
- if(data->bits.urlstringalloc)
- /* the URL is allocated, free it! */
- free(data->url);
+ if(data->free_referer)
+ free(data->referer);
- Curl_cookie_cleanup(data->cookies);
+ if(data->bits.urlstringalloc)
+ /* the URL is allocated, free it! */
+ free(data->url);
- free(data);
+ Curl_cookie_cleanup(data->cookies);
- /* global cleanup */
- curl_free();
- }
-}
+ /* free the connection cache */
+ free(data->connects);
-CURLcode curl_close(CURL *curl)
-{
- struct UrlData *data=(struct UrlData *)curl;
-
- void *protocol = data->proto.generic;
+ free(data);
- /* total session cleanup (frees 'data' as well!)*/
- urlfree(data, TRUE);
-
- if(protocol)
- free(protocol);
+ /* global cleanup */
+ curl_free();
return CURLE_OK;
}
data->in = stdin; /* default input from stdin */
data->err = stderr; /* default stderr to stderr */
- data->firstsocket = -1; /* no file descriptor */
- data->secondarysocket = -1; /* no file descriptor */
-
/* use fwrite as default function to store output */
data->fwrite = (size_t (*)(char *, size_t, size_t, FILE *))fwrite;
data->httpreq = HTTPREQ_GET; /* Default HTTP request */
+ /* create an array with connection data struct pointers */
+ data->numconnects = 5; /* hard-coded right now */
+ data->connects = (struct connectdata **)
+ malloc(sizeof(struct connectdata *) * data->numconnects);
+
+ if(!data->connects) {
+ free(data);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ memset(data->connects, 0, sizeof(struct connectdata *)*data->numconnects);
+
*curl = data;
return CURLE_OK;
}
data->ssl.CAfile = va_arg(param, char *);
data->ssl.CApath = NULL; /*This does not work on windows.*/
break;
+ case CURLOPT_TELNETOPTIONS:
+ data->telnet_options = va_arg(param, struct curl_slist *);
+ break;
default:
/* unknown tag and its companion, just ignore: */
return CURLE_READ_ERROR; /* correct this */
{
struct connectdata *conn = c_connect;
- struct UrlData *data = conn->data;
-
- if(data->proto.generic)
- free(data->proto.generic);
- data->proto.generic=NULL; /* it is gone */
+ if(conn->proto.generic)
+ free(conn->proto.generic);
#ifdef ENABLE_IPV6
if(conn->res) /* host name info */
if(conn->path) /* the URL path part */
free(conn->path);
- free(conn); /* free the connection oriented data */
+#ifdef USE_SSLEAY
+ if (conn->ssl.use) {
+ if(conn->ssl.handle) {
+ (void)SSL_shutdown(conn->ssl.handle);
+ SSL_set_connect_state(conn->ssl.handle);
- /* clean up the sockets and SSL stuff from the previous "round" */
- urlfree(data, FALSE);
+ SSL_free (conn->ssl.handle);
+ conn->ssl.handle = NULL;
+ }
+ if(conn->ssl.ctx) {
+ SSL_CTX_free (conn->ssl.ctx);
+ conn->ssl.ctx = NULL;
+ }
+ conn->ssl.use = FALSE; /* get back to ordinary socket usage */
+ }
+#endif /* USE_SSLEAY */
+
+ /* close possibly still open sockets */
+ if(-1 != conn->secondarysocket) {
+ sclose(conn->secondarysocket);
+ conn->secondarysocket = -1;
+ }
+ if(-1 != conn->firstsocket) {
+ sclose(conn->firstsocket);
+ conn->firstsocket=-1;
+ }
+
+ free(conn); /* free all the connection oriented data */
return CURLE_OK;
}
-static CURLcode _connect(CURL *curl, CURLconnect **in_connect)
+/*
+ * Given one filled in connection struct, this function should detect if there
+ * already is one that have all the significant details exactly the same and
+ * thus should be used instead.
+ */
+static bool
+ConnectionExists(struct UrlData *data,
+ struct connectdata *needle,
+ struct connectdata **usethis)
{
- char *tmp;
- char *buf;
- CURLcode result;
- char resumerange[40]="";
- struct UrlData *data = curl;
+ size_t i;
+ struct connectdata *check;
+
+ for(i=0; i< data->numconnects; i++) {
+ /*
+ * Note that if we use a HTTP proxy, we check connections to that
+ * proxy and not to the actual remote server.
+ */
+ check = data->connects[i];
+ if(!check)
+ /* NULL pointer means not filled-in entry */
+ continue;
+ if(strequal(needle->protostr, check->protostr) &&
+ strequal(needle->name, check->name) &&
+ (needle->port == check->port) ) {
+ *usethis = check;
+ return TRUE; /* yes, we found one to use! */
+ }
+ }
+ return FALSE; /* no matching connecting exists */
+}
+
+/*
+ * This function frees/closes a connection in the connection cache. This
+ * should take the previously set policy into account when deciding which
+ * of the connections to kill.
+ */
+static int
+ConnectionKillOne(struct UrlData *data)
+{
+ size_t i;
struct connectdata *conn;
- char endbracket;
-#ifdef HAVE_SIGACTION
- struct sigaction sigact;
+ int highscore=-1;
+ int connindex=-1;
+ int score;
+ CURLcode result;
+
+ for(i=0; i< data->numconnects; i++) {
+ conn = data->connects[i];
+
+ if(!conn)
+ continue;
+
+ /*
+ * By using the set policy, we score each connection.
+ */
+ switch(data->closepolicy) {
+ default:
+ score = 1; /* not implemented yet */
+ break;
+ }
+
+ if(score > highscore) {
+ highscore = score;
+ connindex = i;
+ }
+ }
+ if(connindex >= 0) {
+
+ /* the winner gets the honour of being disconnected */
+ result = curl_disconnect(data->connects[connindex]);
+
+ /* clean the array entry */
+ data->connects[connindex] = NULL;
+ }
+
+ return connindex; /* return the available index or -1 */
+}
+
+/*
+ * The given input connection struct pointer is to be stored. If the "cache"
+ * is already full, we must clean out the most suitable using the previously
+ * set policy.
+ *
+ * The given connection should be unique. That must've been checked prior to
+ * this call.
+ */
+static unsigned int
+ConnectionStore(struct UrlData *data,
+ struct connectdata *conn)
+{
+ size_t i;
+ for(i=0; i< data->numconnects; i++) {
+ if(!data->connects[i])
+ break;
+ }
+ if(i == data->numconnects)
+ /* there was no room available, kill one */
+ i = ConnectionKillOne(data);
+
+ data->connects[i] = conn; /* fill in this */
+ conn->connectindex = i; /* make the child know where the pointer to this
+ particular data is stored */
+
+ return i;
+}
+
+static CURLcode ConnectPlease(struct UrlData *data,
+ struct connectdata *conn)
+{
+
+#ifndef ENABLE_IPV6
+ conn->firstsocket = socket(AF_INET, SOCK_STREAM, 0);
+
+ memset((char *) &conn->serv_addr, '\0', sizeof(conn->serv_addr));
+ memcpy((char *)&(conn->serv_addr.sin_addr),
+ conn->hp->h_addr, conn->hp->h_length);
+ conn->serv_addr.sin_family = conn->hp->h_addrtype;
+ conn->serv_addr.sin_port = htons(data->port);
#endif
- int urllen;
-#ifdef ENABLE_IPV6
- struct addrinfo *ai;
+
+#if !defined(WIN32)||defined(__CYGWIN32__)
+ /* We don't generally like checking for OS-versions, we should make this
+ HAVE_XXXX based, although at the moment I don't have a decent test for
+ this! */
+
+#ifdef HAVE_INET_NTOA
+
+#ifndef INADDR_NONE
+#define INADDR_NONE (unsigned long) ~0
#endif
+#ifndef ENABLE_IPV6
/*************************************************************
- * Check input data
+ * Select device to bind socket to
*************************************************************/
+ if (data->device && (strlen(data->device)<255)) {
+ struct sockaddr_in sa;
+ struct hostent *h=NULL;
+ char *hostdataptr=NULL;
+ size_t size;
+ char myhost[256] = "";
+ unsigned long in;
- if(!data || (data->handle != STRUCT_OPEN))
- return CURLE_BAD_FUNCTION_ARGUMENT; /* TBD: make error codes */
+ if(Curl_if2ip(data->device, myhost, sizeof(myhost))) {
+ h = Curl_gethost(data, myhost, &hostdataptr);
+ }
+ else {
+ if(strlen(data->device)>1) {
+ h = Curl_gethost(data, data->device, &hostdataptr);
+ }
+ if(h) {
+ /* we know data->device is shorter than the myhost array */
+ strcpy(myhost, data->device);
+ }
+ }
- if(!data->url)
- return CURLE_URL_MALFORMAT;
+ if(! *myhost) {
+ /* need to fix this
+ h=Curl_gethost(data,
+ getmyhost(*myhost,sizeof(myhost)),
+ hostent_buf,
+ sizeof(hostent_buf));
+ */
+ printf("in here\n");
+ }
- /*************************************************************
- * Allocate and initiate a connection struct
- *************************************************************/
- conn = (struct connectdata *)malloc(sizeof(struct connectdata));
- if(!conn) {
- *in_connect = NULL; /* clear the pointer */
- return CURLE_OUT_OF_MEMORY;
- }
- *in_connect = conn;
+ infof(data, "We connect from %s\n", myhost);
- memset(conn, 0, sizeof(struct connectdata));
- conn->handle = STRUCT_CONNECT;
+ if ( (in=inet_addr(myhost)) != INADDR_NONE ) {
+
+ if ( h ) {
+ memset((char *)&sa, 0, sizeof(sa));
+ memcpy((char *)&sa.sin_addr,
+ h->h_addr,
+ h->h_length);
+ sa.sin_family = AF_INET;
+ sa.sin_addr.s_addr = in;
+ sa.sin_port = 0; /* get any port */
+
+ if( bind(conn->firstsocket, (struct sockaddr *)&sa, sizeof(sa)) >= 0) {
+ /* we succeeded to bind */
+ struct sockaddr_in add;
+
+ size = sizeof(add);
+ if(getsockname(conn->firstsocket, (struct sockaddr *) &add,
+ (int *)&size)<0) {
+ failf(data, "getsockname() failed");
+ return CURLE_HTTP_PORT_FAILED;
+ }
+ }
+ else {
+ switch(errno) {
+ case EBADF:
+ failf(data, "Invalid descriptor: %d", errno);
+ break;
+ case EINVAL:
+ failf(data, "Invalid request: %d", errno);
+ break;
+ case EACCES:
+ failf(data, "Address is protected, user not superuser: %d", errno);
+ break;
+ case ENOTSOCK:
+ failf(data,
+ "Argument is a descriptor for a file, not a socket: %d",
+ errno);
+ break;
+ case EFAULT:
+ failf(data, "Inaccessable memory error: %d", errno);
+ break;
+ case ENAMETOOLONG:
+ failf(data, "Address too long: %d", errno);
+ break;
+ case ENOMEM:
+ failf(data, "Insufficient kernel memory was available: %d", errno);
+ break;
+ default:
+ failf(data,"errno %d\n");
+ } /* end of switch */
+
+ return CURLE_HTTP_PORT_FAILED;
+ } /* end of else */
+
+ } /* end of if h */
+ else {
+ failf(data,"could't find my own IP address (%s)", myhost);
+ return CURLE_HTTP_PORT_FAILED;
+ }
+ } /* end of inet_addr */
- conn->data = data; /* remember our daddy */
- conn->state = CONN_INIT;
+ else {
+ failf(data, "could't find my own IP address (%s)", myhost);
+ return CURLE_HTTP_PORT_FAILED;
+ }
- conn->upload_bufsize = UPLOAD_BUFSIZE; /* the smallest upload buffer size
- we use */
+ if(hostdataptr)
+ free(hostdataptr); /* allocated by Curl_gethost() */
- buf = data->buffer; /* this is our buffer */
+ } /* end of device selection support */
+#endif /* end of HAVE_INET_NTOA */
+#endif /* end of not WIN32 */
+#endif /*ENABLE_IPV6*/
/*************************************************************
- * Set signal handler
+ * Connect to server/proxy
*************************************************************/
+#ifdef ENABLE_IPV6
+ data->firstsocket = -1;
+ for (ai = conn->res; ai; ai = ai->ai_next) {
+ data->firstsocket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+ if (data->firstsocket < 0)
+ continue;
+
+ if (connect(data->firstsocket, ai->ai_addr, ai->ai_addrlen) < 0) {
+ close(data->firstsocket);
+ data->firstsocket = -1;
+ continue;
+ }
+
+ break;
+ }
+ if (data->firstsocket < 0) {
+ failf(data, strerror(errno));
+ return CURLE_COULDNT_CONNECT;
+ }
+#else
+ if (connect(conn->firstsocket,
+ (struct sockaddr *) &(conn->serv_addr),
+ sizeof(conn->serv_addr)
+ ) < 0) {
+ switch(errno) {
+#ifdef ECONNREFUSED
+ /* this should be made nicer */
+ case ECONNREFUSED:
+ failf(data, "Connection refused");
+ break;
+ case EFAULT:
+ failf(data, "Invalid socket address: %d",errno);
+ break;
+ case EISCONN:
+ failf(data, "Socket already connected: %d",errno);
+ break;
+ case ETIMEDOUT:
+ failf(data, "Timeout while accepting connection, server busy: %d",errno);
+ break;
+ case ENETUNREACH:
+ failf(data, "Network is unreachable: %d",errno);
+ break;
+ case EADDRINUSE:
+ failf(data, "Local address already in use: %d",errno);
+ break;
+ case EINPROGRESS:
+ failf(data, "Socket is nonblocking and connection can not be completed immediately: %d",errno);
+ break;
+ case EALREADY:
+ failf(data, "Socket is nonblocking and a previous connection attempt not completed: %d",errno);
+ break;
+ case EAGAIN:
+ failf(data, "No more free local ports: %d",errno);
+ break;
+ case EACCES:
+ case EPERM:
+ failf(data, "Attempt to connect to broadcast address without socket broadcast flag or local firewall rule violated: %d",errno);
+ break;
+#endif
+ case EINTR:
+ failf(data, "Connection timed out");
+ break;
+ default:
+ failf(data, "Can't connect to server: %d", errno);
+ break;
+ }
+ return CURLE_COULDNT_CONNECT;
+ }
+#endif
+
+ return CURLE_OK;
+}
+
+
+static CURLcode _connect(CURL *curl, CURLconnect **in_connect)
+{
+ char *tmp;
+ char *buf;
+ CURLcode result;
+ char resumerange[40]="";
+ struct UrlData *data = curl;
+ struct connectdata *conn;
+ struct connectdata *conn_temp;
+ char endbracket;
#ifdef HAVE_SIGACTION
- sigaction(SIGALRM, NULL, &sigact);
- sigact.sa_handler = alarmfunc;
-#ifdef SA_RESTART
- /* HPUX doesn't have SA_RESTART but defaults to that behaviour! */
- sigact.sa_flags &= ~SA_RESTART;
+ struct sigaction sigact;
#endif
- sigaction(SIGALRM, &sigact, NULL);
-#else
- /* no sigaction(), revert to the much lamer signal() */
-#ifdef HAVE_SIGNAL
- signal(SIGALRM, alarmfunc);
+ int urllen;
+#ifdef ENABLE_IPV6
+ struct addrinfo *ai;
#endif
-#endif
+ /*************************************************************
+ * Check input data
+ *************************************************************/
+
+ if(!data || (data->handle != STRUCT_OPEN))
+ return CURLE_BAD_FUNCTION_ARGUMENT; /* TBD: make error codes */
+
+ if(!data->url)
+ return CURLE_URL_MALFORMAT;
+
+ /* First, split up the current URL in parts so that we can use the
+ parts for checking against the already present connections. In order
+ to not have to modify everything at once, we allocate a temporary
+ connection data struct and fill in for comparison purposes. */
+
+ conn = (struct connectdata *)malloc(sizeof(struct connectdata));
+ if(!conn) {
+ *in_connect = NULL; /* clear the pointer */
+ return CURLE_OUT_OF_MEMORY;
+ }
+ /* we have to init the struct */
+ memset(conn, 0, sizeof(struct connectdata));
+
+ /* and we setup a few fields in case we end up actually using this struct */
+ conn->handle = STRUCT_CONNECT; /* this is a connection handle */
+ conn->data = data; /* remember our daddy */
+ conn->state = CONN_INIT; /* init state */
+ conn->upload_bufsize = UPLOAD_BUFSIZE; /* default upload buffer size */
+ conn->firstsocket = -1; /* no file descriptor */
+ conn->secondarysocket = -1; /* no file descriptor */
+ conn->connectindex = -1; /* no index */
/***********************************************************
* We need to allocate memory to store the path in. We get the size of the
* url ...
************************************************************/
if((2 == sscanf(data->url, "%64[^:]://%[^\n]",
- conn->proto,
- conn->path)) && strequal(conn->proto, "file")) {
+ conn->protostr,
+ conn->path)) && strequal(conn->protostr, "file")) {
/*
* we deal with file://<host>/<path> differently since it supports no
* hostname other than "localhost" and "127.0.0.1", which is unique among
* quietly ommitted */
strcpy(conn->path, &conn->path[10]);
- strcpy(conn->proto, "file"); /* store protocol string lowercase */
+ strcpy(conn->protostr, "file"); /* store protocol string lowercase */
}
else {
/* Set default host and default path */
if (2 > sscanf(data->url,
"%64[^\n:]://%256[^\n/]%[^\n]",
- conn->proto, conn->gname, conn->path)) {
+ conn->protostr, conn->gname, conn->path)) {
/*
* The URL was badly formatted, let's try the browser-style _without_
*/
if(strnequal(conn->gname, "FTP", 3)) {
- strcpy(conn->proto, "ftp");
+ strcpy(conn->protostr, "ftp");
}
else if(strnequal(conn->gname, "GOPHER", 6))
- strcpy(conn->proto, "gopher");
+ strcpy(conn->protostr, "gopher");
#ifdef USE_SSLEAY
else if(strnequal(conn->gname, "HTTPS", 5))
- strcpy(conn->proto, "https");
+ strcpy(conn->protostr, "https");
#endif /* USE_SSLEAY */
else if(strnequal(conn->gname, "TELNET", 6))
- strcpy(conn->proto, "telnet");
+ strcpy(conn->protostr, "telnet");
else if (strnequal(conn->gname, "DICT", sizeof("DICT")-1))
- strcpy(conn->proto, "DICT");
+ strcpy(conn->protostr, "DICT");
else if (strnequal(conn->gname, "LDAP", sizeof("LDAP")-1))
- strcpy(conn->proto, "LDAP");
+ strcpy(conn->protostr, "LDAP");
else {
- strcpy(conn->proto, "http");
+ strcpy(conn->protostr, "http");
}
conn->protocol |= PROT_MISSING; /* not given in URL */
}
}
+ buf = data->buffer; /* this is our buffer */
+
+ /*************************************************************
+ * Set signal handler
+ *************************************************************/
+#ifdef HAVE_SIGACTION
+ sigaction(SIGALRM, NULL, &sigact);
+ sigact.sa_handler = alarmfunc;
+#ifdef SA_RESTART
+ /* HPUX doesn't have SA_RESTART but defaults to that behaviour! */
+ sigact.sa_flags &= ~SA_RESTART;
+#endif
+ sigaction(SIGALRM, &sigact, NULL);
+#else
+ /* no sigaction(), revert to the much lamer signal() */
+#ifdef HAVE_SIGNAL
+ signal(SIGALRM, alarmfunc);
+#endif
+
+#endif
+
/*************************************************************
* Take care of user and password authentication stuff
*************************************************************/
*************************************************************/
conn->name = conn->gname;
conn->ppath = conn->path;
- data->hostname = conn->name;
+ conn->hostname = conn->name;
/*************************************************************
}
if(!nope) {
/* It was not listed as without proxy */
- char *protop = conn->proto;
+ char *protop = conn->protostr;
char *envp = proxy_env;
char *prox;
*/
char *reurl;
- reurl = aprintf("%s://%s", conn->proto, data->url);
+ reurl = aprintf("%s://%s", conn->protostr, data->url);
if(!reurl)
return CURLE_OUT_OF_MEMORY;
* Setup internals depending on protocol
*************************************************************/
- if (strequal(conn->proto, "HTTP")) {
+ if (strequal(conn->protostr, "HTTP")) {
if(!data->port)
data->port = PORT_HTTP;
data->remote_port = PORT_HTTP;
conn->curl_done = Curl_http_done;
conn->curl_close = Curl_http_close;
}
- else if (strequal(conn->proto, "HTTPS")) {
+ else if (strequal(conn->protostr, "HTTPS")) {
#ifdef USE_SSLEAY
if(!data->port)
data->port = PORT_HTTPS;
return CURLE_UNSUPPORTED_PROTOCOL;
#endif /* !USE_SSLEAY */
}
- else if (strequal(conn->proto, "GOPHER")) {
+ else if (strequal(conn->protostr, "GOPHER")) {
if(!data->port)
data->port = PORT_GOPHER;
data->remote_port = PORT_GOPHER;
conn->curl_done = Curl_http_done;
conn->curl_close = Curl_http_close;
}
- else if(strequal(conn->proto, "FTP")) {
+ else if(strequal(conn->protostr, "FTP")) {
char *type;
if(!data->port)
data->port = PORT_FTP;
}
}
}
- else if(strequal(conn->proto, "TELNET")) {
+ else if(strequal(conn->protostr, "TELNET")) {
/* telnet testing factory */
conn->protocol |= PROT_TELNET;
if(!data->port)
conn->curl_done = Curl_telnet_done;
}
- else if (strequal(conn->proto, "DICT")) {
+ else if (strequal(conn->protostr, "DICT")) {
conn->protocol |= PROT_DICT;
if(!data->port)
data->port = PORT_DICT;
conn->curl_do = Curl_dict;
conn->curl_done = Curl_dict_done;
}
- else if (strequal(conn->proto, "LDAP")) {
+ else if (strequal(conn->protostr, "LDAP")) {
conn->protocol |= PROT_LDAP;
if(!data->port)
data->port = PORT_LDAP;
conn->curl_do = Curl_ldap;
conn->curl_done = Curl_ldap_done;
}
- else if (strequal(conn->proto, "FILE")) {
+ else if (strequal(conn->protostr, "FILE")) {
conn->protocol |= PROT_FILE;
conn->curl_do = file;
else {
/* We fell through all checks and thus we don't support the specified
protocol */
- failf(data, "Unsupported protocol: %s", conn->proto);
+ failf(data, "Unsupported protocol: %s", conn->protostr);
return CURLE_UNSUPPORTED_PROTOCOL;
}
* .netrc scanning coming up
*************************************************************/
if(data->bits.use_netrc) {
- if(Curl_parsenetrc(data->hostname, data->user, data->passwd)) {
+ if(Curl_parsenetrc(conn->hostname, data->user, data->passwd)) {
infof(data, "Couldn't find host %s in the .netrc file, using defaults",
- data->hostname);
+ conn->hostname);
}
else
data->bits.user_passwd = 1; /* enable user+password */
data->remote_port = atoi(tmp);
}
+ /* copy the port-specifics to the connection struct */
+ conn->port = data->port;
+ conn->remote_port = data->remote_port;
+
+ /*************************************************************
+ * Check the current list of connections to see if we can
+ * re-use an already existing one or if we have to create a
+ * new one.
+ *************************************************************/
+
+ if(ConnectionExists(data, conn, &conn_temp)) {
+ /*
+ * We already have a connection for this, we got the former connection
+ * in the conn_temp variable and thus we need to cleanup the one we
+ * just allocated before we can move along and use the previously
+ * existing one.
+ */
+ char *path = conn->path; /* setup the current path pointer properly */
+ free(conn); /* we don't need this new one */
+ conn = conn_temp; /* use this connection from now on */
+ free(conn->path); /* free the previous path pointer */
+ conn->path = path; /* use this one */
+ conn->ppath = path; /* set this too */
+ }
+ else {
+ /*
+ * This is a brand new connection, so let's store it in the connection
+ * cache of ours!
+ */
+ ConnectionStore(data, conn);
+ }
+ *in_connect = conn;
+
/*************************************************************
* Resolve the name of the server or proxy
*************************************************************/
* there, thus overriding any defaults that might have been set above. */
data->port = data->remote_port; /* it is the same port */
- /* Connect to target host right on */
+ /* Resolve target host right on */
#ifdef ENABLE_IPV6
- conn->res = Curl_getaddrinfo(data, conn->name, data->port);
+ if(!conn->res)
+ /* it might already be set if reusing a connection */
+ conn->res = Curl_getaddrinfo(data, conn->name, data->port);
if(!conn->res)
#else
- conn->hp = Curl_gethost(data, conn->name, &conn->hostent_buf);
+ if(!conn->hp)
+ /* it might already be set if reusing a connection */
+ conn->hp = Curl_gethost(data, conn->name, &conn->hostent_buf);
if(!conn->hp)
#endif
{
return CURLE_COULDNT_RESOLVE_HOST;
}
}
- else {
+ else if(!conn->hp) {
+ /* This is a proxy that hasn't been resolved yet. It may be resolved
+ if we're reusing an existing connection. */
#ifdef ENABLE_IPV6
failf(data, "proxy yet to be supported");
return CURLE_OUT_OF_MEMORY;
data->port = data->proxyport;
}
- /* connect to proxy */
+ /* resolve proxy */
conn->hp = Curl_gethost(data, proxyptr, &conn->hostent_buf);
if(!conn->hp) {
failf(data, "Couldn't resolve proxy '%s'", proxyptr);
}
Curl_pgrsTime(data, TIMER_NAMELOOKUP);
-#ifndef ENABLE_IPV6
- data->firstsocket = socket(AF_INET, SOCK_STREAM, 0);
-
- memset((char *) &conn->serv_addr, '\0', sizeof(conn->serv_addr));
- memcpy((char *)&(conn->serv_addr.sin_addr),
- conn->hp->h_addr, conn->hp->h_length);
- conn->serv_addr.sin_family = conn->hp->h_addrtype;
- conn->serv_addr.sin_port = htons(data->port);
-#endif
-
-#if !defined(WIN32)||defined(__CYGWIN32__)
- /* We don't generally like checking for OS-versions, we should make this
- HAVE_XXXX based, although at the moment I don't have a decent test for
- this! */
-
-#ifdef HAVE_INET_NTOA
-
-#ifndef INADDR_NONE
-#define INADDR_NONE (unsigned long) ~0
-#endif
-
-#ifndef ENABLE_IPV6
- /*************************************************************
- * Select device to bind socket to
- *************************************************************/
- if (data->device && (strlen(data->device)<255)) {
- struct sockaddr_in sa;
- struct hostent *h=NULL;
- char *hostdataptr=NULL;
- size_t size;
- char myhost[256] = "";
- unsigned long in;
-
- if(Curl_if2ip(data->device, myhost, sizeof(myhost))) {
- h = Curl_gethost(data, myhost, &hostdataptr);
- }
- else {
- if(strlen(data->device)>1) {
- h = Curl_gethost(data, data->device, &hostdataptr);
- }
- if(h) {
- /* we know data->device is shorter than the myhost array */
- strcpy(myhost, data->device);
- }
- }
-
- if(! *myhost) {
- /* need to fix this
- h=Curl_gethost(data,
- getmyhost(*myhost,sizeof(myhost)),
- hostent_buf,
- sizeof(hostent_buf));
- */
- printf("in here\n");
- }
-
- infof(data, "We connect from %s\n", myhost);
-
- if ( (in=inet_addr(myhost)) != INADDR_NONE ) {
-
- if ( h ) {
- memset((char *)&sa, 0, sizeof(sa));
- memcpy((char *)&sa.sin_addr,
- h->h_addr,
- h->h_length);
- sa.sin_family = AF_INET;
- sa.sin_addr.s_addr = in;
- sa.sin_port = 0; /* get any port */
-
- if( bind(data->firstsocket, (struct sockaddr *)&sa, sizeof(sa)) >= 0) {
- /* we succeeded to bind */
- struct sockaddr_in add;
-
- size = sizeof(add);
- if(getsockname(data->firstsocket, (struct sockaddr *) &add,
- (int *)&size)<0) {
- failf(data, "getsockname() failed");
- return CURLE_HTTP_PORT_FAILED;
- }
- }
- else {
- switch(errno) {
- case EBADF:
- failf(data, "Invalid descriptor: %d", errno);
- break;
- case EINVAL:
- failf(data, "Invalid request: %d", errno);
- break;
- case EACCES:
- failf(data, "Address is protected, user not superuser: %d", errno);
- break;
- case ENOTSOCK:
- failf(data,
- "Argument is a descriptor for a file, not a socket: %d",
- errno);
- break;
- case EFAULT:
- failf(data, "Inaccessable memory error: %d", errno);
- break;
- case ENAMETOOLONG:
- failf(data, "Address too long: %d", errno);
- break;
- case ENOMEM:
- failf(data, "Insufficient kernel memory was available: %d", errno);
- break;
- default:
- failf(data,"errno %d\n");
- } /* end of switch */
-
- return CURLE_HTTP_PORT_FAILED;
- } /* end of else */
-
- } /* end of if h */
- else {
- failf(data,"could't find my own IP address (%s)", myhost);
- return CURLE_HTTP_PORT_FAILED;
- }
- } /* end of inet_addr */
-
- else {
- failf(data, "could't find my own IP address (%s)", myhost);
- return CURLE_HTTP_PORT_FAILED;
- }
-
- if(hostdataptr)
- free(hostdataptr); /* allocated by Curl_gethost() */
-
- } /* end of device selection support */
-#endif /* end of HAVE_INET_NTOA */
-#endif /* end of not WIN32 */
-#endif /*ENABLE_IPV6*/
-
- /*************************************************************
- * Connect to server/proxy
- *************************************************************/
-#ifdef ENABLE_IPV6
- data->firstsocket = -1;
- for (ai = conn->res; ai; ai = ai->ai_next) {
- data->firstsocket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
- if (data->firstsocket < 0)
- continue;
-
- if (connect(data->firstsocket, ai->ai_addr, ai->ai_addrlen) < 0) {
- close(data->firstsocket);
- data->firstsocket = -1;
- continue;
- }
-
- break;
- }
- if (data->firstsocket < 0) {
- failf(data, strerror(errno));
- return CURLE_COULDNT_CONNECT;
- }
-#else
- if (connect(data->firstsocket,
- (struct sockaddr *) &(conn->serv_addr),
- sizeof(conn->serv_addr)
- ) < 0) {
- switch(errno) {
-#ifdef ECONNREFUSED
- /* this should be made nicer */
- case ECONNREFUSED:
- failf(data, "Connection refused");
- break;
- case EFAULT:
- failf(data, "Invalid socket address: %d",errno);
- break;
- case EISCONN:
- failf(data, "Socket already connected: %d",errno);
- break;
- case ETIMEDOUT:
- failf(data, "Timeout while accepting connection, server busy: %d",errno);
- break;
- case ENETUNREACH:
- failf(data, "Network is unreachable: %d",errno);
- break;
- case EADDRINUSE:
- failf(data, "Local address already in use: %d",errno);
- break;
- case EINPROGRESS:
- failf(data, "Socket is nonblocking and connection can not be completed immediately: %d",errno);
- break;
- case EALREADY:
- failf(data, "Socket is nonblocking and a previous connection attempt not completed: %d",errno);
- break;
- case EAGAIN:
- failf(data, "No more free local ports: %d",errno);
- break;
- case EACCES:
- case EPERM:
- failf(data, "Attempt to connect to broadcast address without socket broadcast flag or local firewall rule violated: %d",errno);
- break;
-#endif
- case EINTR:
- failf(data, "Connection timed out");
- break;
- default:
- failf(data, "Can't connect to server: %d", errno);
- break;
- }
- return CURLE_COULDNT_CONNECT;
+ if(-1 == conn->firstsocket) {
+ /* Connect only if not already connected! */
+ result = ConnectPlease(data, conn);
+ if(CURLE_OK != result)
+ return result;
}
-#endif
/*************************************************************
* Proxy authentication
struct connectdata *conn = c_connect;
struct UrlData *data;
CURLcode result;
+ int index;
if(!conn || (conn->handle!= STRUCT_CONNECT)) {
return CURLE_BAD_FUNCTION_ARGUMENT;
conn->state = CONN_DONE;
+ /* if bits.close is TRUE, it means that the connection should be closed
+ in spite of all our efforts to be nice */
+ if((CURLE_OK == result) && conn->bits.close) {
+ index = conn->connectindex; /* get the index */
+ result = curl_disconnect(conn); /* close the connection */
+ data->connects[index]=NULL; /* clear the pointer */
+ }
+
return result;
}
};
#endif
+/* struct for data related to SSL and SSL connections */
+struct ssl_connect_data {
+ bool use; /* use ssl encrypted communications TRUE/FALSE */
+#ifdef USE_SSLEAY
+ /* these ones requires specific SSL-types */
+ SSL_CTX* ctx;
+ SSL* handle;
+ X509* server_cert;
+#endif /* USE_SSLEAY */
+};
+
+struct ssl_config_data {
+ long version; /* what version the client wants to use */
+ long certverifyresult; /* result from the certificate verification */
+ long verifypeer; /* set TRUE if this is desired */
+ char *CApath; /* DOES NOT WORK ON WINDOWS */
+ char *CAfile; /* cerficate to verify peer against */
+};
+
+/****************************************************************************
+ * HTTP unique setup
+ ***************************************************************************/
+struct HTTP {
+ struct FormData *sendit;
+ int postsize;
+ char *p_pragma; /* Pragma: string */
+ char *p_accept; /* Accept: string */
+ long readbytecount;
+ long writebytecount;
+
+ /* For FORM posting */
+ struct Form form;
+ size_t (*storefread)(char *, size_t , size_t , FILE *);
+ FILE *in;
+};
+
+/****************************************************************************
+ * FTP unique setup
+ ***************************************************************************/
+struct FTP {
+ long *bytecountp;
+ char *user; /* user name string */
+ char *passwd; /* password string */
+ char *urlpath; /* the originally given path part of the URL */
+ char *dir; /* decoded directory */
+ char *file; /* decoded file */
+};
+
+/*
+ * Boolean values that concerns this connection.
+ */
+struct ConnectBits {
+ bool close; /* if set, we close the connection after this request */
+};
+
/*
* The connectdata struct contains all fields and variables that should be
* unique for an entire connection.
Handle handle; /* struct identifier */
struct UrlData *data; /* link to the root CURL struct */
+ int connectindex; /* what index in the connects index this particular
+ struct has */
+
/**** curl_connect() phase fields */
ConnState state; /* for state dependent actions */
struct hostent *hp;
struct sockaddr_in serv_addr;
#endif
- char proto[64]; /* store the protocol string in this buffer */
+ char protostr[64]; /* store the protocol string in this buffer */
char gname[257]; /* store the hostname in this buffer */
char *name; /* host name pointer to fool around with */
char *path; /* allocated buffer to store the URL's path part in */
+ char *hostname; /* hostname to connect, as parsed from url */
+ long port; /* which port to use locally */
+ unsigned short remote_port; /* what remote port to connect to,
+ not the proxy port! */
char *ppath;
long bytecount;
struct timeval now; /* current time */
+ int firstsocket; /* the main socket to use */
+ int secondarysocket; /* for i.e ftp transfers */
long upload_bufsize; /* adjust as you see fit, never bigger than BUFSIZE
never smaller than UPLOAD_BUFSIZE */
+ struct ssl_connect_data ssl; /* this is for ssl-stuff */
+
+ struct ConnectBits bits; /* various state-flags for this connection */
+
/* These two functions MUST be set by the curl_connect() function to be
be protocol dependent */
CURLcode (*curl_do)(struct connectdata *connect);
the same we read from. -1 disables */
long *writebytecountp; /* return number of bytes written or NULL */
+
#ifdef KRB4
enum protection_level command_prot;
void *app_data;
#endif
+
+ /*************** Request - specific items ************/
+ /* previously this was in the urldata struct */
+ union {
+ struct HTTP *http;
+ struct HTTP *gopher; /* alias, just for the sake of being more readable */
+ struct HTTP *https; /* alias, just for the sake of being more readable */
+ struct FTP *ftp;
+#if 0 /* no need for special ones for these: */
+ struct TELNET *telnet;
+ struct FILE *file;
+ struct LDAP *ldap;
+ struct DICT *dict;
+#endif
+ void *generic;
+ } proto;
+
+
};
struct Progress {
int speeder_c;
};
-/****************************************************************************
- * HTTP unique setup
- ***************************************************************************/
-struct HTTP {
- struct FormData *sendit;
- int postsize;
- char *p_pragma; /* Pragma: string */
- char *p_accept; /* Accept: string */
- long readbytecount;
- long writebytecount;
-
- /* For FORM posting */
- struct Form form;
- size_t (*storefread)(char *, size_t , size_t , FILE *);
- FILE *in;
-};
-
-/****************************************************************************
- * FTP unique setup
- ***************************************************************************/
-struct FTP {
- long *bytecountp;
- char *user; /* user name string */
- char *passwd; /* password string */
- char *urlpath; /* the originally given path part of the URL */
- char *dir; /* decoded directory */
- char *file; /* decoded file */
-};
-
typedef enum {
HTTPREQ_NONE, /* first in list */
HTTPREQ_GET,
CURLI_LAST
} CurlInterface;
-/* struct for data related to SSL and SSL connections */
-struct ssldata {
- bool use; /* use ssl encrypted communications TRUE/FALSE */
- long version; /* what version the client wants to use */
- long certverifyresult; /* result from the certificate verification */
- long verifypeer; /* set TRUE if this is desired */
- char *CApath; /* DOES NOT WORK ON WINDOWS */
- char *CAfile; /* cerficate to verify peer against */
-#ifdef USE_SSLEAY
- /* these ones requires specific SSL-types */
- SSL_CTX* ctx;
- SSL* handle;
- X509* server_cert;
-#endif /* USE_SSLEAY */
-};
-
/*
* As of April 11, 2000 we're now trying to split up the urldata struct in
* three different parts:
* 3 - Request-specific. Variables that are of interest for this particular
* transfer being made right now.
*
+ * In Febrary 2001, this is being done stricter. The 'connectdata' struct
+ * MUST have all the connection oriented stuff as we may now have several
+ * simultaneous connections and connection structs in memory.
*/
struct UrlData {
char *errorbuffer; /* store failure messages in here */
/*************** Session - specific items ************/
- char *proxy; /* if proxy, set it here, set CONF_PROXY to use this */
+ char *proxy; /* if proxy, set it here */
char *proxyuserpwd; /* Proxy <user:password>, if used */
long proxyport; /* If non-zero, use this port number by default. If the
proxy string features a ":[port]" that one will override
long header_size; /* size of read header(s) in bytes */
long request_size; /* the amount of bytes sent in the request(s) */
- /*************** Request - specific items ************/
-
- union {
- struct HTTP *http;
- struct HTTP *gopher; /* alias, just for the sake of being more readable */
- struct HTTP *https; /* alias, just for the sake of being more readable */
- struct FTP *ftp;
-#if 0 /* no need for special ones for these: */
- struct TELNET *telnet;
- struct FILE *file;
- struct LDAP *ldap;
- struct DICT *dict;
-#endif
- void *generic;
- } proto;
-
FILE *out; /* the fetched file goes here */
FILE *in; /* the uploaded file is read from here */
FILE *writeheader; /* write the header to this is non-NULL */
char *url; /* what to get */
char *freethis; /* if non-NULL, an allocated string for the URL */
- char *hostname; /* hostname to connect, as parsed from url */
- long port; /* which port to use (if non-protocol bind) set
- CONF_PORT to use this */
+ long port; /* which port to use (if non-protocol bind) */
unsigned short remote_port; /* what remote port to connect to, not the proxy
port! */
struct Configbits bits; /* new-style (v7) flag data */
+ struct ssl_config_data ssl; /* this is for ssl-stuff */
char *userpwd; /* <user:password>, if used */
char *range; /* range, if used. See README for detailed specification on
long maxdownload; /* in bytes, the maximum amount of data to fetch, 0
means unlimited */
- /* fields only set and used within _urlget() */
- int firstsocket; /* the main socket to use */
- int secondarysocket; /* for i.e ftp transfers */
-
char buffer[BUFSIZE+1]; /* buffer with size BUFSIZE */
double current_speed; /* the ProgressShow() funcion sets this */
struct CookieInfo *cookies;
- struct ssldata ssl; /* this is for ssl-stuff */
-
long crlf;
struct curl_slist *quote; /* before the transfer */
struct curl_slist *postquote; /* after the transfer */
+ /* Telnet negotiation options */
+ struct curl_slist *telnet_options; /* linked list of telnet options */
+
TimeCond timecondition; /* kind of comparison */
time_t timevalue; /* what time to compare with */
char *headerbuff; /* allocated buffer to store headers in */
int headersize; /* size of the allocation */
-#if 0
- /* this was removed in libcurl 7.4 */
- char *writeinfo; /* if non-NULL describes what to output on a successful
- completion */
-#endif
-
struct Progress progress; /* for all the progress meter data */
#define MAX_CURL_USER_LENGTH 128
#endif
struct timeval keeps_speed; /* this should be request-specific */
+
+ /* 'connects' will be an allocated array with pointers. If the pointer is
+ set, it holds an allocated connection. */
+ struct connectdata **connects;
+ size_t numconnects; /* size of the 'connects' array */
+ curl_closepolicy closepolicy;
+
};
#define LIBCURL_NAME "libcurl"
#define CONF_NOBODY (1<<11) /* use HEAD to get http document */
#define CONF_FAILONERROR (1<<12) /* no output on http error codes >= 300 */
#define CONF_UPLOAD (1<<14) /* this is an upload */
-#define CONF_POST (1<<15) /* HTTP POST method */
#define CONF_FTPLISTONLY (1<<16) /* Use NLST when listing ftp dir */
#define CONF_FTPAPPEND (1<<20) /* Append instead of overwrite on upload! */
#define CONF_NETRC (1<<22) /* read user+password from .netrc */
#define CONF_FOLLOWLOCATION (1<<23) /* use Location: Luke! */
#define CONF_GETTEXT (1<<24) /* use ASCII/text for transfer */
#define CONF_HTTPPOST (1<<25) /* multipart/form-data HTTP POST */
-#if 0
-#define CONF_PUT (1<<27) /* PUT the input file */
-#endif
+
#define CONF_MUTE (1<<28) /* force NOPROGRESS */
#ifndef HAVE_STRDUP
" -r/--range <range> Retrieve a byte range from a HTTP/1.1 or FTP server\n"
" -s/--silent Silent mode. Don't output anything\n"
" -S/--show-error Show error. With -s, make curl show errors when they occur\n"
+ " -t/--telnet-option <OPT=val> Set telnet option\n"
" -T/--upload-file <file> Transfer/upload <file> to remote site\n"
" --url <URL> Another way to specify URL to work with\n"
" -u/--user <user[:password]> Specify user and password to use\n"
struct HttpPost *httppost;
struct HttpPost *last_post;
+ struct curl_slist *telnet_options;
+
HttpReq httpreq;
};
{"r", "range", TRUE},
{"s", "silent", FALSE},
{"S", "show-error", FALSE},
- {"t", "upload", FALSE},
+ {"t", "telnet-options", TRUE},
{"T", "upload-file", TRUE},
{"u", "user", TRUE},
{"U", "proxy-user", TRUE},
else
config->postfields=postdata;
}
- if(config->postfields)
- config->conf |= CONF_POST;
+
if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq))
return PARAM_BAD_USE;
break;
config->showerror ^= TRUE; /* toggle on if used with -s */
break;
case 't':
- /* we are uploading */
- config->conf ^= CONF_UPLOAD;
- fprintf(stderr, "-t is a deprecated switch, use '-T -' instead!\n");
+ /* Telnet options */
+ config->telnet_options = curl_slist_append(config->telnet_options, nextarg);
break;
case 'T':
/* we are uploading */
curl_easy_setopt(curl, CURLOPT_FAILONERROR,
config->conf&CONF_FAILONERROR);
curl_easy_setopt(curl, CURLOPT_UPLOAD, config->conf&CONF_UPLOAD);
- curl_easy_setopt(curl, CURLOPT_POST, config->conf&CONF_POST);
curl_easy_setopt(curl, CURLOPT_FTPLISTONLY,
config->conf&CONF_FTPLISTONLY);
curl_easy_setopt(curl, CURLOPT_FTPAPPEND, config->conf&CONF_FTPAPPEND);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION,
config->conf&CONF_FOLLOWLOCATION);
curl_easy_setopt(curl, CURLOPT_TRANSFERTEXT, config->conf&CONF_GETTEXT);
-#if 0
- curl_easy_setopt(curl, CURLOPT_PUT, config->conf&CONF_PUT);
-#endif
curl_easy_setopt(curl, CURLOPT_MUTE, config->conf&CONF_MUTE);
curl_easy_setopt(curl, CURLOPT_USERPWD, config->userpwd);
curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd);
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &progressbar);
}
+ /* new in libcurl 7.6.2: */
+ curl_easy_setopt(curl, CURLOPT_TELNETOPTIONS, config->telnet_options);
+
res = curl_easy_perform(curl);
if(config->writeout) {
#define CURL_NAME "curl"
-#define CURL_VERSION "7.6.1"
+#define CURL_VERSION "7.7-alpha1"
#define CURL_ID CURL_NAME " " CURL_VERSION " (" OS ") "
Date: Thu, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake
Location: data/110002.txt?coolsite=yes
+Connection: close
This server reply is for testing a simple Location: following