static int tcp_read(tcpcon_t *tc, void *buf, size_t len, int all, net_read_cb_t *cb, void *opaque) { int x; size_t off = 0; while(1) { size_t r = len - off; x = netRecv(tc->fd, buf + off, r, 0); if(x < 1) return -1; if(all) { off += x; if(off == len) return len; if(cb != NULL) if(cb(opaque, off)) return -1; } else { return x; } } }
// Attempt to receive on an established client connection, returns true if it received something bool telnetRecv(JsNetwork *net) { if (tnSrv.sock == 0 || tnSrv.cliSock == 0) return false; char buff[256]; int r = netRecv(net, tnSrv.cliSock, buff, 256); if (r > 0) { jshPushIOCharEvents(EV_TELNET, buff, r); } else if (r < 0) { telnetRelease(net); } if (r != 0) { //printf("tnSrv: recv sock=%d, %d bytes\n", tnSrv.sock, r); } return r != 0; }
static int tcp_read(tcpcon_t *tc, void *buf, size_t len, int all) { int x; size_t off = 0; while(1) { size_t r = MIN(65536, len - off); x = netRecv(tc->fd, buf + off, r, all ? MSG_WAITALL : 0); if(x <= 0) return -1; if(all) { off += x; if(off == len) return len; } else { return x < 1 ? -1 : x; } } }
ssize_t netRecvGeneral(NetPath *netPath, Octet *buf, TimeInternal *time) { return netRecv(buf, time, &netPath->generalQ); }
ssize_t netRecvEvent(NetPath *netPath, Octet *buf, TimeInternal *time) { return netRecv(buf, time, &netPath->eventQ); }
bool socketClientConnectionsIdle(JsNetwork *net) { char *buf = alloca(net->chunkSize); // allocate on stack JsVar *arr = socketGetArray(HTTP_ARRAY_HTTP_CLIENT_CONNECTIONS,false); if (!arr) return false; bool hadSockets = false; JsvObjectIterator it; jsvObjectIteratorNew(&it, arr); while (jsvObjectIteratorHasValue(&it)) { hadSockets = true; // Get connection, socket, and socket type // For normal sockets, socket==connection, but for HTTP connection is httpCRq and socket is httpCRs JsVar *connection = jsvObjectIteratorGetValue(&it); SocketType socketType = socketGetType(connection); JsVar *socket = ((socketType&ST_TYPE_MASK)==ST_HTTP) ? jsvObjectGetChild(connection,HTTP_NAME_RESPONSE_VAR,0) : jsvLockAgain(connection); bool socketClosed = false; JsVar *receiveData = 0; bool hadHeaders = false; int error = 0; // error code received from netXxxx functions bool isHttp = (socketType&ST_TYPE_MASK) == ST_HTTP; bool closeConnectionNow = jsvGetBoolAndUnLock(jsvObjectGetChild(connection, HTTP_NAME_CLOSENOW, false)); bool alreadyConnected = jsvGetBoolAndUnLock(jsvObjectGetChild(connection, HTTP_NAME_CONNECTED, false)); int sckt = (int)jsvGetIntegerAndUnLock(jsvObjectGetChild(connection,HTTP_NAME_SOCKET,0))-1; // so -1 if undefined if (sckt>=0) { if (isHttp) hadHeaders = jsvGetBoolAndUnLock(jsvObjectGetChild(connection,HTTP_NAME_HAD_HEADERS,0)); else hadHeaders = true; receiveData = jsvObjectGetChild(connection,HTTP_NAME_RECEIVE_DATA,0); /* We do this up here because we want to wait until we have been once * around the idle loop (=callbacks have been executed) before we run this */ if (hadHeaders) socketClientPushReceiveData(connection, socket, &receiveData); JsVar *sendData = jsvObjectGetChild(connection,HTTP_NAME_SEND_DATA,0); if (!closeConnectionNow) { // send data if possible if (sendData && !jsvIsEmptyString(sendData)) { // don't try to send if we're already in error state int num = 0; if (error == 0) num = socketSendData(net, connection, sckt, &sendData); if (num > 0 && !alreadyConnected && !isHttp) { // whoa, we sent something, must be connected! jsiQueueObjectCallbacks(connection, HTTP_NAME_ON_CONNECT, &connection, 1); jsvObjectSetChildAndUnLock(connection, HTTP_NAME_CONNECTED, jsvNewFromBool(true)); alreadyConnected = true; } if (num < 0) { closeConnectionNow = true; error = num; } jsvObjectSetChild(connection, HTTP_NAME_SEND_DATA, sendData); // _http_send prob updated sendData } else { // no data to send, do we want to close? do so. if (jsvGetBoolAndUnLock(jsvObjectGetChild(connection, HTTP_NAME_CLOSE, false))) closeConnectionNow = true; } // Now read data if possible (and we have space for it) if (!receiveData || !hadHeaders) { int num = netRecv(net, sckt, buf, net->chunkSize); //if (num != 0) printf("recv returned %d\r\n", num); if (!alreadyConnected && num == SOCKET_ERR_NO_CONN) { ; // ignore... it's just telling us we're not connected yet } else if (num < 0) { closeConnectionNow = true; error = num; // disconnected without headers? error. if (!hadHeaders && error == SOCKET_ERR_CLOSED) error = SOCKET_ERR_NO_RESP; } else { // did we just get connected? if (!alreadyConnected && !isHttp) { jsiQueueObjectCallbacks(connection, HTTP_NAME_ON_CONNECT, &connection, 1); jsvObjectSetChildAndUnLock(connection, HTTP_NAME_CONNECTED, jsvNewFromBool(true)); alreadyConnected = true; // if we do not have any data to send, issue a drain event if (!sendData || (int)jsvGetStringLength(sendData) == 0) jsiQueueObjectCallbacks(connection, HTTP_NAME_ON_DRAIN, &connection, 1); } // got data add it to our receive buffer if (num > 0) { if (!receiveData) { receiveData = jsvNewFromEmptyString(); jsvObjectSetChild(connection, HTTP_NAME_RECEIVE_DATA, receiveData); } if (receiveData) { // could be out of memory jsvAppendStringBuf(receiveData, buf, (size_t)num); if ((socketType&ST_TYPE_MASK)==ST_HTTP && !hadHeaders) { // for HTTP see whether we now have full response headers JsVar *resVar = jsvObjectGetChild(connection,HTTP_NAME_RESPONSE_VAR,0); if (httpParseHeaders(&receiveData, resVar, false)) { hadHeaders = true; jsvObjectSetChildAndUnLock(connection, HTTP_NAME_HAD_HEADERS, jsvNewFromBool(hadHeaders)); jsiQueueObjectCallbacks(connection, HTTP_NAME_ON_CONNECT, &resVar, 1); } jsvUnLock(resVar); jsvObjectSetChild(connection, HTTP_NAME_RECEIVE_DATA, receiveData); } } } } } jsvUnLock(sendData); } } if (closeConnectionNow) { socketClientPushReceiveData(connection, socket, &receiveData); if (!receiveData) { if ((socketType&ST_TYPE_MASK) != ST_HTTP) jsiQueueObjectCallbacks(socket, HTTP_NAME_ON_END, &socket, 1); // If we had data to send but the socket closed, this is an error JsVar *sendData = jsvObjectGetChild(connection,HTTP_NAME_SEND_DATA,0); if (sendData && jsvGetStringLength(sendData) > 0 && error == SOCKET_ERR_CLOSED) error = SOCKET_ERR_UNSENT_DATA; jsvUnLock(sendData); _socketConnectionKill(net, connection); JsVar *connectionName = jsvObjectIteratorGetKey(&it); jsvObjectIteratorNext(&it); jsvRemoveChild(arr, connectionName); jsvUnLock(connectionName); socketClosed = true; // fire error event, if there is an error bool hadError = fireErrorEvent(error, connection, NULL); // close callback must happen after error callback JsVar *params[1] = { jsvNewFromBool(hadError) }; jsiQueueObjectCallbacks(socket, HTTP_NAME_ON_CLOSE, params, 1); jsvUnLock(params[0]); } } if (!socketClosed) { jsvObjectIteratorNext(&it); } jsvUnLock3(receiveData, connection, socket); } jsvUnLock(arr); return hadSockets; }
bool socketServerConnectionsIdle(JsNetwork *net) { char *buf = alloca(net->chunkSize); // allocate on stack JsVar *arr = socketGetArray(HTTP_ARRAY_HTTP_SERVER_CONNECTIONS,false); if (!arr) return false; bool hadSockets = false; JsvObjectIterator it; jsvObjectIteratorNew(&it, arr); while (jsvObjectIteratorHasValue(&it)) { hadSockets = true; // Get connection, socket, and socket type // For normal sockets, socket==connection, but for HTTP we split it into a request and a response JsVar *connection = jsvObjectIteratorGetValue(&it); SocketType socketType = socketGetType(connection); JsVar *socket = ((socketType&ST_TYPE_MASK)==ST_HTTP) ? jsvObjectGetChild(connection,HTTP_NAME_RESPONSE_VAR,0) : jsvLockAgain(connection); int sckt = (int)jsvGetIntegerAndUnLock(jsvObjectGetChild(connection,HTTP_NAME_SOCKET,0))-1; // so -1 if undefined bool closeConnectionNow = jsvGetBoolAndUnLock(jsvObjectGetChild(connection, HTTP_NAME_CLOSENOW, false)); int error = 0; if (!closeConnectionNow) { int num = netRecv(net, sckt, buf, net->chunkSize); if (num<0) { // we probably disconnected so just get rid of this closeConnectionNow = true; error = num; } else { // add it to our request string if (num>0) { JsVar *receiveData = jsvObjectGetChild(connection,HTTP_NAME_RECEIVE_DATA,0); JsVar *oldReceiveData = receiveData; if (!receiveData) receiveData = jsvNewFromEmptyString(); if (receiveData) { jsvAppendStringBuf(receiveData, buf, (size_t)num); bool hadHeaders = jsvGetBoolAndUnLock(jsvObjectGetChild(connection,HTTP_NAME_HAD_HEADERS,0)); if (!hadHeaders && httpParseHeaders(&receiveData, connection, true)) { hadHeaders = true; jsvObjectSetChildAndUnLock(connection, HTTP_NAME_HAD_HEADERS, jsvNewFromBool(hadHeaders)); JsVar *server = jsvObjectGetChild(connection,HTTP_NAME_SERVER_VAR,0); JsVar *args[2] = { connection, socket }; jsiQueueObjectCallbacks(server, HTTP_NAME_ON_CONNECT, args, ((socketType&ST_TYPE_MASK)==ST_HTTP) ? 2 : 1); jsvUnLock(server); } if (hadHeaders && !jsvIsEmptyString(receiveData)) { // Keep track of how much we received (so we can close once we have it) if ((socketType&ST_TYPE_MASK)==ST_HTTP) { jsvObjectSetChildAndUnLock(connection, HTTP_NAME_RECEIVE_COUNT, jsvNewFromInteger( jsvGetIntegerAndUnLock(jsvObjectGetChild(connection, HTTP_NAME_RECEIVE_COUNT, JSV_INTEGER)) + jsvGetStringLength(receiveData) )); } // execute 'data' callback or save data if (jswrap_stream_pushData(connection, receiveData, false)) { // clear received data jsvUnLock(receiveData); receiveData = 0; } } // if received data changed, update it if (receiveData != oldReceiveData) jsvObjectSetChild(connection,HTTP_NAME_RECEIVE_DATA,receiveData); jsvUnLock(receiveData); } } } // send data if possible JsVar *sendData = jsvObjectGetChild(socket,HTTP_NAME_SEND_DATA,0); if (sendData && !jsvIsEmptyString(sendData)) { int sent = socketSendData(net, socket, sckt, &sendData); // FIXME? checking for errors is a bit iffy. With the esp8266 network that returns // varied error codes we'd want to skip SOCKET_ERR_CLOSED and let the recv side deal // with normal closing so we don't miss the tail of what's received, but other drivers // return -1 (which is the same value) for all errors. So we rely on the check ~12 lines // down if(num>0)closeConnectionNow=false instead. if (sent < 0) { closeConnectionNow = true; error = sent; } jsvObjectSetChild(socket, HTTP_NAME_SEND_DATA, sendData); // socketSendData prob updated sendData } // only close if we want to close, have no data to send, and aren't receiving data bool wantClose = jsvGetBoolAndUnLock(jsvObjectGetChild(socket,HTTP_NAME_CLOSE,0)); if (wantClose && (!sendData || jsvIsEmptyString(sendData)) && num<=0) { bool reallyCloseNow = true; if ((socketType&ST_TYPE_MASK)==ST_HTTP) { // Check if we had a Content-Length header - if so, we need to wait until we have received that amount JsVar *headers = jsvObjectGetChild(connection,"headers",0); if (headers) { JsVarInt contentLength = jsvGetIntegerAndUnLock(jsvObjectGetChild(headers,"Content-Length",0)); JsVarInt contentReceived = jsvGetIntegerAndUnLock(jsvObjectGetChild(connection, HTTP_NAME_RECEIVE_COUNT, 0)); if (contentLength > contentReceived) { reallyCloseNow = false; } jsvUnLock(headers); } } closeConnectionNow = reallyCloseNow; } else if (num > 0) closeConnectionNow = false; // guarantee that anything received is processed jsvUnLock(sendData); } if (closeConnectionNow) { // send out any data that we were POSTed JsVar *receiveData = jsvObjectGetChild(connection,HTTP_NAME_RECEIVE_DATA,0); bool hadHeaders = jsvGetBoolAndUnLock(jsvObjectGetChild(connection,HTTP_NAME_HAD_HEADERS,0)); if (hadHeaders && !jsvIsEmptyString(receiveData)) { // execute 'data' callback or save data jswrap_stream_pushData(connection, receiveData, true); } jsvUnLock(receiveData); // fire error events bool hadError = fireErrorEvent(error, connection, socket); // fire the close listeners JsVar *params[1] = { jsvNewFromBool(hadError) }; jsiQueueObjectCallbacks(connection, HTTP_NAME_ON_CLOSE, params, 1); jsiQueueObjectCallbacks(socket, HTTP_NAME_ON_CLOSE, params, 1); jsvUnLock(params[0]); _socketConnectionKill(net, connection); JsVar *connectionName = jsvObjectIteratorGetKey(&it); jsvObjectIteratorNext(&it); jsvRemoveChild(arr, connectionName); jsvUnLock(connectionName); } else jsvObjectIteratorNext(&it); jsvUnLock2(connection, socket); } jsvObjectIteratorFree(&it); jsvUnLock(arr); return hadSockets; }
static void handleclient(u64 conn_s_p) { // todo: clean up int conn_s = (int)conn_s_p; int list_s_data = -1; int conn_s_data = -1; int datareq = 0; char cwd[256]; char rnfr[256]; char filename[256]; char user[32]; u32 rest = 0; int authd = 0; int active = 1; Lv2FsFile tempfd; char buf[BUFFER_SIZE]; char buffer[1024]; char client_cmd[8][128]; ssize_t bytes; #if LOGIN_CHECK == 1 // load password file char passwordcheck[33]; // check if password file exists - if not, use default password if(exists(PASSWORD_FPATH) == 0) { Lv2FsFile fd; u64 read; lv2FsOpen(PASSWORD_FPATH, LV2_O_RDONLY, &fd, 0, NULL, 0); lv2FsRead(fd, passwordcheck, 32, &read); lv2FsClose(fd); if(strlen(passwordcheck) != 32) { strcpy(passwordcheck, LOGIN_PASSWORD); } } else { strcpy(passwordcheck, LOGIN_PASSWORD); } #endif // start directory strcpy(cwd, "/"); // welcome message swritel(conn_s, "220-OpenPS3FTP by @jjolano\r\n"); sprintf(buffer, "220 Version %s\r\n", VERSION); swritel(conn_s, buffer); while(exitapp == 0 && active && (bytes = sreadl(conn_s, buffer, 1024)) > 0) { // get rid of the newline at the end of the string buffer[strcspn(buffer, "\n")] = '\0'; buffer[strcspn(buffer, "\r")] = '\0'; // parse received string into array int parameter_count = 0; char *result = strtok(buffer, " "); strcpy(client_cmd[0], result); while(parameter_count < 7 && (result = strtok(NULL, " ")) != NULL) { parameter_count++; strcpy(client_cmd[parameter_count], result); } // identify the command int cmd_id; for(cmd_id = 0; cmd_id < client_cmds_count; cmd_id++) { if(strcasecmp(client_cmd[0], client_cmds[cmd_id]) == 0) { break; } } // execute command if(authd == 0) { // not logged in switch(cmd_id) { case 0: // USER #if LOGIN_CHECK == 1 if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } strcpy(user, client_cmd[1]); sprintf(buffer, "331 User %s OK. Password required\r\n", user); swritel(conn_s, buffer); } else { swritel(conn_s, "501 Please provide a username\r\n"); } #else sprintf(buffer, "331 User %s OK. Password (not really) required\r\n", user); swritel(conn_s, buffer); #endif break; case 1: // PASS #if LOGIN_CHECK == 1 if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } // hash the password given char output[33]; md5(output, client_cmd[1]); if(strcmp(user, LOGIN_USERNAME) == 0 && strcmp(output, passwordcheck) == 0) { swritel(conn_s, "230 Successful authentication\r\n"); authd = 1; } else { swritel(conn_s, "430 Invalid username or password - \r\n"); } } else { swritel(conn_s, "501 Invalid username or password\r\n"); } #else swritel(conn_s, "230 Successful authentication\r\n"); authd = 1; #endif break; case 2: // QUIT swritel(conn_s, "221 See you later\r\n"); active = 0; break; default: swritel(conn_s, "530 You are not logged in\r\n"); } } else { // logged in switch(cmd_id) { case 0: // USER case 1: // PASS swritel(conn_s, "530 You are already logged in\r\n"); break; case 2: // QUIT swritel(conn_s, "221 See you later\r\n"); active = 0; break; case 3: // PASV rest = 0; netSocketInfo snf; int ret = netGetSockInfo(conn_s, &snf, 1); if(ret >= 0 && snf.local_adr.s_addr != 0) { // assign a random port for passive mode srand(conn_s); int rand1 = (rand() % 251) + 4; int rand2 = rand() % 256; sprintf(buffer, "227 Entering Passive Mode (%u,%u,%u,%u,%i,%i)\r\n", (snf.local_adr.s_addr & 0xFF000000) >> 24, (snf.local_adr.s_addr & 0xFF0000) >> 16, (snf.local_adr.s_addr & 0xFF00) >> 8, (snf.local_adr.s_addr & 0xFF), rand1, rand2); short int pasvport = (rand1 * 256) + rand2; struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(pasvport); list_s_data = netSocket(AF_INET, SOCK_STREAM, 0); netBind(list_s_data, (struct sockaddr *) &servaddr, sizeof(servaddr)); netListen(list_s_data, 1); swritel(conn_s, buffer); if((conn_s_data = netAccept(list_s_data, NULL, NULL)) == -1) { swritel(conn_s, "550 PASV command failed\r\n"); } else { datareq = 1; } break; } swritel(conn_s, "550 PASV command failed\r\n"); break; case 4: // PORT if(parameter_count == 1) { rest = 0; char connectinfo[32]; strcpy(connectinfo, client_cmd[1]); char data[7][4]; int i = 0; char *result = strtok(connectinfo, ","); strcpy(data[0], result); while(i < 6 && (result = strtok(NULL, ",")) != NULL) { i++; strcpy(data[i], result); } char conn_ipaddr[16]; sprintf(conn_ipaddr, "%s.%s.%s.%s", data[0], data[1], data[2], data[3]); struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons((atoi(data[4]) * 256) + atoi(data[5])); inet_pton(AF_INET, conn_ipaddr, &servaddr.sin_addr); conn_s_data = netSocket(AF_INET, SOCK_STREAM, 0); if(connect(conn_s_data, (struct sockaddr *)&servaddr, sizeof(servaddr)) == 0) { swritel(conn_s, "200 PORT command successful\r\n"); datareq = 1; } else { swritel(conn_s, "550 PORT command failed\r\n"); } } else { swritel(conn_s, "501 Syntax error\r\n"); } break; case 5: // SITE if(strcasecmp(client_cmd[1], "CHMOD") == 0) { int i; for(i = 4; i <= parameter_count; i++) { strcat(client_cmd[3], " "); strcat(client_cmd[3], client_cmd[i]); } absPath(filename, client_cmd[3], cwd); char perms[4]; sprintf(perms, "0%s", client_cmd[2]); if(lv2FsChmod(filename, S_IFMT | strtol(perms, NULL, 8)) == 0) { swritel(conn_s, "250 File permissions successfully set\r\n"); } else { swritel(conn_s, "550 Failed to set file permissions\r\n"); } } else { swritel(conn_s, "500 Unrecognized SITE command\r\n"); } break; case 6: // FEAT swritel(conn_s, "211- Extensions supported:\r\n"); int i; for(i = 0; i < feat_cmds_count; i++) { sprintf(buffer, " %s\r\n", feat_cmds[i]); swritel(conn_s, buffer); } swritel(conn_s, "211 End.\r\n"); break; case 7: // TYPE swritel(conn_s, "200 TYPE command successful\r\n"); break; case 8: // REST if(parameter_count == 1) { rest = atoi(client_cmd[1]); swritel(conn_s, "350 REST command successful\r\n"); } else { swritel(conn_s, "501 Syntax error\r\n"); } break; case 9: // RETR if(parameter_count >= 1) { if(conn_s_data == -1) { swritel(conn_s, "425 No data connection\r\n"); break; } swritel(conn_s, "150 Opening data connection\r\n"); int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } absPath(filename, client_cmd[1], cwd); u64 pos; u64 read = -1; Lv2FsFile fd; lv2FsOpen(filename, LV2_O_RDONLY, &fd, 0, NULL, 0); lv2FsLSeek64(fd, (s64)rest, SEEK_SET, &pos); if(fd >= 0) { while(lv2FsRead(fd, buf, BUFFER_SIZE - 1, &read) == 0 && read > 0) { netSend(conn_s_data, buf, read, 0); } if(read == 0) { swritel(conn_s, "226 Transfer complete\r\n"); } else { swritel(conn_s, "426 Transfer failed\r\n"); } } else { swritel(conn_s, "452 File access error\r\n"); } lv2FsClose(fd); } else { swritel(conn_s, "501 Syntax error\r\n"); } break; case 10: // PWD sprintf(buffer, "257 \"%s\" is the current directory\r\n", cwd); swritel(conn_s, buffer); break; case 11: // CWD if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } strcpy(filename, client_cmd[1]); if(strcmp(filename, "../") == 0) { for(int i = strlen(cwd) - 2; i > 0; i--) { if(cwd[i] != '/') { cwd[i] = '\0'; } else { break; } } sprintf(buffer, "250 Directory change successful: %s\r\n", cwd); swritel(conn_s, buffer); break; } if(filename[0] == '/') { strcpy(cwd, (strlen(filename) == 1) ? "/" : filename); } else { strcat(cwd, filename); } if(cwd[strlen(cwd) - 1] != '/') { strcat(cwd, "/"); } if(isDir(cwd)) { sprintf(buffer, "250 Directory change successful: %s\r\n", cwd); } else { sprintf(buffer, "550 Could not change directory: %s\r\n", cwd); } swritel(conn_s, buffer); } else { sprintf(buffer, "257 \"%s\" is the current directory\r\n", cwd); swritel(conn_s, buffer); } break; case 12: // CDUP for(int i = strlen(cwd) - 2; i > 0; i--) { if(cwd[i] != '/') { cwd[i] = '\0'; } else { break; } } sprintf(buffer, "250 Directory change successful: %s\r\n", cwd); swritel(conn_s, buffer); break; case 13: // NLST if(conn_s_data == -1) { swritel(conn_s, "425 No data connection\r\n"); break; } swritel(conn_s, "150 Opening data connection\r\n"); if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } absPath(filename, client_cmd[1], cwd); } else { strcpy(filename, cwd); } if(lv2FsOpenDir(filename, &tempfd) == 0) { u64 read; Lv2FsDirent ent; while(lv2FsReadDir(tempfd, &ent, &read) == 0 && read != 0) { sprintf(buffer, "%s\r\n", ent.d_name); swritel(conn_s_data, buffer); } swritel(conn_s, "226 Transfer complete\r\n"); } else { swritel(conn_s, "451 Cannot access directory\r\n"); } lv2FsCloseDir(tempfd); break; case 14: // LIST if(conn_s_data == -1) { swritel(conn_s, "425 No data connection\r\n"); break; } swritel(conn_s, "150 Opening data connection\r\n"); if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } absPath(filename, client_cmd[1], cwd); } else { strcpy(filename, cwd); } if(lv2FsOpenDir(filename, &tempfd) == 0) { u64 read; Lv2FsDirent ent; while(lv2FsReadDir(tempfd, &ent, &read) == 0 && read != 0) { sprintf(filename, "%s%s", cwd, ent.d_name); Lv2FsStat entry; lv2FsStat(filename, &entry); struct tm *tm; char timebuf[32]; tm = localtime(&entry.st_mtime); strftime(timebuf, 31, "%b %d %Y", tm); sprintf(buffer, "%s%s%s%s%s%s%s%s%s%s 1 root root %lu %s %s\r\n", ((entry.st_mode & S_IFDIR) != 0)?"d":"-", ((entry.st_mode & S_IRUSR) != 0)?"r":"-", ((entry.st_mode & S_IWUSR) != 0)?"w":"-", ((entry.st_mode & S_IXUSR) != 0)?"x":"-", ((entry.st_mode & S_IRGRP) != 0)?"r":"-", ((entry.st_mode & S_IWGRP) != 0)?"w":"-", ((entry.st_mode & S_IXGRP) != 0)?"x":"-", ((entry.st_mode & S_IROTH) != 0)?"r":"-", ((entry.st_mode & S_IWOTH) != 0)?"w":"-", ((entry.st_mode & S_IXOTH) != 0)?"x":"-", (long unsigned int)entry.st_size, timebuf, ent.d_name); swritel(conn_s_data, buffer); } swritel(conn_s, "226 Transfer complete\r\n"); } else { swritel(conn_s, "451 Cannot access directory\r\n"); } lv2FsCloseDir(tempfd); break; case 15: // STOR if(parameter_count >= 1) { if(conn_s_data == -1) { swritel(conn_s, "425 No data connection\r\n"); break; } swritel(conn_s, "150 Opening data connection\r\n"); int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } absPath(filename, client_cmd[1], cwd); u64 pos; u64 read = -1; u64 write = -1; Lv2FsFile fd; lv2FsOpen(filename, LV2_O_WRONLY | LV2_O_CREAT, &fd, 0, NULL, 0); lv2FsChmod(filename, S_IFMT | 0666); lv2FsLSeek64(fd, (s32)rest, SEEK_SET, &pos); if(fd >= 0) { while((read = (u64)netRecv(conn_s_data, buf, BUFFER_SIZE - 1, MSG_WAITALL)) > 0) { lv2FsWrite(fd, buf, read, &write); if(write != read) { break; } } if(read == 0) { swritel(conn_s, "226 Transfer complete\r\n"); } else { swritel(conn_s, "426 Transfer failed\r\n"); } } else { swritel(conn_s, "452 File access error\r\n"); } lv2FsClose(fd); } else { swritel(conn_s, "501 Syntax error\r\n"); } break; case 16: // NOOP swritel(conn_s, "200 Zzzz...\r\n"); break; case 17: // DELE if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } absPath(filename, client_cmd[1], cwd); if(lv2FsUnlink(filename) == 0) { swritel(conn_s, "250 File successfully deleted\r\n"); } else { swritel(conn_s, "550 Failed to delete file\r\n"); } } else { swritel(conn_s, "501 Syntax error\r\n"); } break; case 18: // MKD if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } absPath(filename, client_cmd[1], cwd); if(lv2FsMkdir(filename, 0775) == 0) { swritel(conn_s, "250 Directory successfully created\r\n"); } else { swritel(conn_s, "550 Failed to create directory\r\n"); } } else { swritel(conn_s, "501 Syntax error\r\n"); } break; case 19: // RMD if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } absPath(filename, client_cmd[1], cwd); if(lv2FsRmdir(filename) == 0) { swritel(conn_s, "250 Directory successfully deleted\r\n"); } else { swritel(conn_s, "550 Failed to remove directory\r\n"); } } else { swritel(conn_s, "501 Syntax error\r\n"); } break; case 20: // RNFR if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } absPath(rnfr, client_cmd[1], cwd); if(exists(rnfr) == 0) { swritel(conn_s, "350 RNFR successful - ready for destination\r\n"); } else { swritel(conn_s, "550 RNFR failed - file does not exist\r\n"); } } else { swritel(conn_s, "501 Syntax error\r\n"); } break; case 21: // RNTO if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } absPath(filename, client_cmd[1], cwd); if(lv2FsRename(rnfr, filename) == 0) { swritel(conn_s, "250 File successfully renamed\r\n"); } else { swritel(conn_s, "550 Failed to rename file\r\n"); } } else { swritel(conn_s, "501 Syntax error\r\n"); } break; case 22: // SIZE if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } absPath(filename, client_cmd[1], cwd); Lv2FsStat entry; if(lv2FsStat(filename, &entry) == 0) { sprintf(buffer, "213 %lu\r\n", (long unsigned int)entry.st_size); } else { sprintf(buffer, "550 Requested file doesn't exist\r\n"); } swritel(conn_s, buffer); } else { swritel(conn_s, "501 Syntax error\r\n"); } break; case 23: // SYST swritel(conn_s, "215 UNIX Type: L8\r\n"); break; case 24: // HELP swritel(conn_s, "214 No help for you.\r\n"); break; case 25: // PASSWD if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } // hash the password given char output[33]; md5(output, client_cmd[1]); Lv2FsFile fd; u64 written; lv2FsOpen(PASSWORD_FPATH, LV2_O_WRONLY | LV2_O_CREAT, &fd, 0, NULL, 0); lv2FsWrite(fd, output, 32, &written); lv2FsClose(fd); swritel(conn_s, "200 Password successfully changed\r\n"); } else { swritel(conn_s, "501 Invalid password\r\n"); } break; case 26: // MLSD if(conn_s_data == -1) { swritel(conn_s, "425 No data connection\r\n"); break; } swritel(conn_s, "150 Opening data connection\r\n"); if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } absPath(filename, client_cmd[1], cwd); } else { strcpy(filename, cwd); } if(lv2FsOpenDir(filename, &tempfd) == 0) { u64 read; Lv2FsDirent ent; while(lv2FsReadDir(tempfd, &ent, &read) == 0 && read != 0) { sprintf(filename, "%s%s", cwd, ent.d_name); Lv2FsStat entry; lv2FsStat(filename, &entry); struct tm *tm; char timebuf[32]; tm = localtime(&entry.st_mtime); strftime(timebuf, 31, "%Y%m%d%H%M%S", tm); int permint = 0; permint += (((entry.st_mode & S_IRUSR) != 0)?400:0) + (((entry.st_mode & S_IWUSR) != 0)?200:0) + (((entry.st_mode & S_IXUSR) != 0)?100:0); permint += (((entry.st_mode & S_IRGRP) != 0)?40:0) + (((entry.st_mode & S_IWGRP) != 0)?20:0) + (((entry.st_mode & S_IXGRP) != 0)?10:0); permint += (((entry.st_mode & S_IROTH) != 0)?4:0) + (((entry.st_mode & S_IWOTH) != 0)?2:0) + (((entry.st_mode & S_IXOTH) != 0)?1:0); sprintf(buffer, "type=%s;size=%lu;modify=%s;UNIX.mode=0%i;UNIX.uid=root;UNIX.gid=root; %s\r\n", ((entry.st_mode & S_IFDIR) != 0)?"dir":"file", (long unsigned int)entry.st_size, timebuf, permint, ent.d_name); swritel(conn_s_data, buffer); } swritel(conn_s, "226 Transfer complete\r\n"); } else { swritel(conn_s, "501 Directory access error\r\n"); } lv2FsCloseDir(tempfd); break; case 27: // MLST swritel(conn_s, "250- Listing directory"); if(parameter_count >= 1) { int i; for(i = 2; i <= parameter_count; i++) { strcat(client_cmd[1], " "); strcat(client_cmd[1], client_cmd[i]); } absPath(filename, client_cmd[1], cwd); } else { strcpy(filename, cwd); } if(lv2FsOpenDir(filename, &tempfd) == 0) { u64 read; Lv2FsDirent ent; while(lv2FsReadDir(tempfd, &ent, &read) == 0 && read != 0) { sprintf(filename, "%s%s", cwd, ent.d_name); Lv2FsStat entry; lv2FsStat(filename, &entry); struct tm *tm; char timebuf[32]; tm = localtime(&entry.st_mtime); strftime(timebuf, 31, "%Y%m%d%H%M%S", tm); int permint = 0; permint += (((entry.st_mode & S_IRUSR) != 0)?400:0) + (((entry.st_mode & S_IWUSR) != 0)?200:0) + (((entry.st_mode & S_IXUSR) != 0)?100:0); permint += (((entry.st_mode & S_IRGRP) != 0)?40:0) + (((entry.st_mode & S_IWGRP) != 0)?20:0) + (((entry.st_mode & S_IXGRP) != 0)?10:0); permint += (((entry.st_mode & S_IROTH) != 0)?4:0) + (((entry.st_mode & S_IWOTH) != 0)?2:0) + (((entry.st_mode & S_IXOTH) != 0)?1:0); sprintf(buffer, " type=%s;size=%lu;modify=%s;UNIX.mode=0%i;UNIX.uid=root;UNIX.gid=root; %s\r\n", ((entry.st_mode & S_IFDIR) != 0)?"dir":"file", (long unsigned int)entry.st_size, timebuf, permint, ent.d_name); swritel(conn_s, buffer); } } swritel(conn_s, "250 End\r\n"); lv2FsCloseDir(tempfd); break; case 28: // EXITAPP swritel(conn_s, "221 Exiting OpenPS3FTP, bye\r\n"); exitapp = 1; break; case 29: // TEST swritel(conn_s, "211-Listing parameters\r\n"); sprintf(buffer, "211-Count: %i\r\n", parameter_count); swritel(conn_s, buffer); int tx; for(tx = 0; tx <= parameter_count; tx++) { sprintf(buffer, " %i:%s\r\n", tx, client_cmd[tx]); swritel(conn_s, buffer); } swritel(conn_s, "211 End\r\n"); break; default: swritel(conn_s, "500 Unrecognized command\r\n"); } if(datareq == 1) { datareq = 0; } else { // close any active data connections if(conn_s_data > -1) { netShutdown(conn_s_data, 2); netClose(conn_s_data); conn_s_data = -1; } if(list_s_data > -1) { netShutdown(list_s_data, 2); netClose(list_s_data); list_s_data = -1; } } } }