Newer
Older
state->rbytes = (ssize_t)recvfrom(state->sockfd,
Daniel Stenberg
committed
(void *)state->rpacket.data,
state->blksize+4,
0,
(struct sockaddr *)&fromaddr,
&fromlen);
if(state->remote_addrlen==0) {
memcpy(&state->remote_addr, &fromaddr, fromlen);
state->remote_addrlen = fromlen;
}
/* Sanity check packet length */
Daniel Stenberg
committed
failf(data, "Received too short packet");
/* Not a timeout, but how best to handle it? */
event = TFTP_EVENT_TIMEOUT;
Daniel Stenberg
committed
}
else {
/* The event is given by the TFTP packet time */
event = (tftp_event_t)getrpacketevent(&state->rpacket);
switch(event) {
case TFTP_EVENT_DATA:
/* Don't pass to the client empty or retransmitted packets */
Daniel Stenberg
committed
((state->block+1) == getrpacketblock(&state->rpacket))) {
Daniel Stenberg
committed
code = Curl_client_write(conn, CLIENTWRITE_BODY,
Daniel Stenberg
committed
(char *)state->rpacket.data+4,
Daniel Stenberg
committed
state->rbytes-4);
if(code)
return code;
k->bytecount += state->rbytes-4;
Curl_pgrsSetDownloadCounter(data, (curl_off_t) k->bytecount);
Daniel Stenberg
committed
}
break;
case TFTP_EVENT_ERROR:
state->error = (tftp_error_t)getrpacketblock(&state->rpacket);
Daniel Stenberg
committed
infof(data, "%s\n", (const char *)state->rpacket.data+4);
Daniel Stenberg
committed
break;
case TFTP_EVENT_ACK:
break;
Daniel Stenberg
committed
case TFTP_EVENT_OACK:
code = tftp_parse_option_ack(state,
(const char *)state->rpacket.data+2,
state->rbytes-2);
if(code)
return code;
break;
Daniel Stenberg
committed
case TFTP_EVENT_RRQ:
case TFTP_EVENT_WRQ:
default:
Daniel Stenberg
committed
failf(data, "%s", "Internal error: Unexpected packet");
Daniel Stenberg
committed
break;
}
/* Update the progress meter */
if(Curl_pgrsUpdate(conn))
return CURLE_ABORTED_BY_CALLBACK;
}
/* Check for transfer timeout every 10 blocks, or after timeout */
if(check_time%10==0) {
time_t current;
time(¤t);
if(current>state->max_time) {
DEBUGF(infof(data, "timeout: %d > %d\n",
current, state->max_time));
state->error = TFTP_ERR_TIMEOUT;
state->state = TFTP_STATE_FIN;
}
}
}
/* Tell curl we're done */
code = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
if(code)
return code;
/* If we have encountered an error */
if(state->error != TFTP_ERR_NONE) {
/* Translate internal error codes to curl error codes */
switch(state->error) {
case TFTP_ERR_NOTFOUND:
code = CURLE_TFTP_NOTFOUND;
break;
case TFTP_ERR_PERM:
code = CURLE_TFTP_PERM;
break;
case TFTP_ERR_DISKFULL:
code = CURLE_REMOTE_DISK_FULL;
break;
case TFTP_ERR_UNDEF:
case TFTP_ERR_ILLEGAL:
code = CURLE_TFTP_ILLEGAL;
break;
case TFTP_ERR_UNKNOWNID:
code = CURLE_TFTP_UNKNOWNID;
break;
case TFTP_ERR_EXISTS:
code = CURLE_REMOTE_FILE_EXISTS;
break;
case TFTP_ERR_NOSUCHUSER:
code = CURLE_TFTP_NOSUCHUSER;
break;
case TFTP_ERR_TIMEOUT:
code = CURLE_OPERATION_TIMEDOUT;
break;
case TFTP_ERR_NORESPONSE:
code = CURLE_COULDNT_CONNECT;
break;
default:
code= CURLE_ABORTED_BY_CALLBACK;
break;
}
}
else
code = CURLE_OK;
return code;
}
Patrick Monnerat
committed
static CURLcode tftp_setup_connection(struct connectdata * conn)
Patrick Monnerat
committed
{
struct SessionHandle *data = conn->data;
char * type;
char command;
conn->socktype = SOCK_DGRAM; /* UDP datagram based */
/* TFTP URLs support an extension like ";mode=<typecode>" that
* we'll try to get now! */
Daniel Stenberg
committed
type = strstr(data->state.path, ";mode=");
Patrick Monnerat
committed
Patrick Monnerat
committed
type = strstr(conn->host.rawalloc, ";mode=");
Patrick Monnerat
committed
*type = 0; /* it was in the middle of the hostname */
command = Curl_raw_toupper(type[6]);
Patrick Monnerat
committed
switch (command) {
case 'A': /* ASCII mode */
case 'N': /* NETASCII mode */
data->set.prefer_ascii = TRUE;
break;
case 'O': /* octet mode */
case 'I': /* binary mode */
default:
/* switch off ASCII */
data->set.prefer_ascii = FALSE;
break;
}
}
return CURLE_OK;
}