working server/client connection and copy file - #3
Conversation
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
There was a problem hiding this comment.
Code review is billed via overage credits. To resume reviews, an organization admin can raise the monthly limit at claude.ai/admin-settings/claude-code.
Once credits are available, push a new commit or reopen this pull request to trigger a review.
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 0 minutes and 59 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (7)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| buffer[strcspn(buffer, "\r\n")] = 0; | ||
| if (!strcmp(buffer, "get")){ | ||
| printf("sending get\n"); | ||
| send(serverFd, "get", 1024, 0); |
There was a problem hiding this comment.
🔴 send() reads 1024 bytes from 4-byte string literal "get", causing buffer over-read
send(serverFd, "get", 1024, 0) specifies a length of 1024 bytes, but the string literal "get" is only 4 bytes (including null terminator). This causes send to read 1020 bytes of adjacent read-only memory, leaking process memory contents over the network (similar in nature to Heartbleed). The same pattern exists at kilo.c:1323 with "ACK".
| send(serverFd, "get", 1024, 0); | |
| send(serverFd, "get", strlen("get"), 0); |
Was this helpful? React with 👍 or 👎 to provide feedback.
Debug
| return; | ||
| } | ||
| fprintf(file, "%s\n", buffer); | ||
| send(fd, "ACK", 1024, 0); //why are we sending this? |
There was a problem hiding this comment.
🔴 send() reads 1024 bytes from 4-byte string literal "ACK", causing buffer over-read
send(fd, "ACK", 1024, 0) specifies a length of 1024 bytes, but the string literal "ACK" is only 4 bytes. This reads 1020 bytes past the literal, leaking memory contents over the network.
| send(fd, "ACK", 1024, 0); //why are we sending this? | |
| send(fd, "ACK", strlen("ACK"), 0); |
Was this helpful? React with 👍 or 👎 to provide feedback.
Debug
| //start editor | ||
| initEditor(); | ||
| editorSelectSyntaxHighlight("transfer"); | ||
| editorOpen(argv[1]); |
There was a problem hiding this comment.
🔴 editorOpen(argv[1]) opens hostname instead of the transferred file "transfer"
editorOpen(argv[1]) opens the file named by the first argument, which is the server hostname (e.g., "localhost"). The transferred file is written to "transfer" (see kilo.c:1307), and syntax highlighting is set for "transfer" at kilo.c:1377, but the editor opens the wrong file. This should be editorOpen("transfer").
| editorOpen(argv[1]); | |
| editorOpen("transfer"); |
Was this helpful? React with 👍 or 👎 to provide feedback.
Debug
| n = read(fd, buffer, 1024); | ||
| buffer[n] = '\0'; |
There was a problem hiding this comment.
🔴 receiveFile() uses read() return value as index without checking for error (-1)
At kilo.c:1310-1311, n = read(fd, buffer, 1024) may return -1 on error, but the code immediately does buffer[n] = '\0' without checking. When n == -1, this writes to buffer[-1], an out-of-bounds memory write.
| n = read(fd, buffer, 1024); | |
| buffer[n] = '\0'; | |
| n = read(fd, buffer, 1023); | |
| if (n <= 0) { fclose(file); return; } | |
| buffer[n] = '\0'; |
Was this helpful? React with 👍 or 👎 to provide feedback.
Debug
| } | ||
| printf("Connected\n"); |
There was a problem hiding this comment.
🔴 No check for connection failure after address traversal loop
After the for loop at kilo.c:1352-1358, there is no check whether traverser is NULL (meaning all connection attempts failed). The code unconditionally prints "Connected" and proceeds to use serverFd, which may hold a socket from a failed connect() call or be uninitialized if all socket() calls failed.
| } | |
| printf("Connected\n"); | |
| } | |
| if (!traverser) { | |
| fprintf(stderr, "Error: Could not connect to server.\n"); | |
| freeaddrinfo(res); | |
| return 1; | |
| } | |
| printf("Connected\n"); |
Was this helpful? React with 👍 or 👎 to provide feedback.
Debug
| struct sockaddr_in cliAddr; | ||
| len = sizeof(cliAddr); | ||
| while (true){ | ||
| int clientFd = accept(serverFd, (struct sockaddr *)&serverAddr, &len); |
There was a problem hiding this comment.
🔴 accept() writes client address into serverAddr, corrupting server's own address
accept(serverFd, (struct sockaddr *)&serverAddr, &len) passes &serverAddr instead of the declared &cliAddr (declared at server.cpp:133). This overwrites the server's address structure with the client's address. Additionally, len was set from sizeof(cliAddr) at line 134 which happens to be the same size, but semantically cliAddr should be used.
| int clientFd = accept(serverFd, (struct sockaddr *)&serverAddr, &len); | |
| int clientFd = accept(serverFd, (struct sockaddr *)&cliAddr, &len); |
Was this helpful? React with 👍 or 👎 to provide feedback.
Debug
|
|
||
| // Create thread to deal with client | ||
| pthread_t thread; | ||
| pthread_create(&thread, NULL, threadFunc, (void *)&clientFd); |
There was a problem hiding this comment.
🔴 Race condition: pointer to loop-local clientFd passed to thread
pthread_create(&thread, NULL, threadFunc, (void *)&clientFd) passes the address of clientFd, a variable local to the while(true) loop body at server.cpp:136. The new thread dereferences this pointer at server.cpp:61, but by that time the main thread may have already looped back and overwritten clientFd with the next accept() result. The thread may read the wrong file descriptor.
Prompt for agents
In server.cpp main() at line 140, a pointer to the local variable clientFd is passed to the new thread. Since the main thread immediately continues to the next accept() call, the clientFd value may be overwritten before the new thread reads it at line 61. Fix this by either: (1) heap-allocating the fd (int *fdPtr = new int(clientFd)) and freeing it in the thread, or (2) casting the int value directly to void* (using intptr_t) and casting back in the thread function.
Was this helpful? React with 👍 or 👎 to provide feedback.
Debug
| while ((n = read(clientFd, buffer, 1024)) > 0){ | ||
| string line(buffer); |
There was a problem hiding this comment.
🔴 Buffer from read() not null-terminated before constructing std::string
At server.cpp:66-67, read(clientFd, buffer, 1024) does not null-terminate buffer, but string line(buffer) constructs a string from a C-string expecting a null terminator. This reads past the valid data into uninitialized buffer memory, producing garbage in the string and potentially reading out of bounds.
| while ((n = read(clientFd, buffer, 1024)) > 0){ | |
| string line(buffer); | |
| while ((n = read(clientFd, buffer, 1023)) > 0){ | |
| buffer[n] = '\0'; | |
| string line(buffer); |
Was this helpful? React with 👍 or 👎 to provide feedback.
Debug
| int val; | ||
| if (setsockopt(serverFd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(int))){ |
There was a problem hiding this comment.
🔴 setsockopt(SO_REUSEADDR) uses uninitialized val variable
int val; at server.cpp:99 is never initialized. setsockopt(serverFd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(int)) at line 100 reads this uninitialized memory. SO_REUSEADDR requires a non-zero value to enable the option. If val happens to be 0, the option won't be set; otherwise it's undefined behavior.
| int val; | |
| if (setsockopt(serverFd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(int))){ | |
| int val = 1; | |
| if (setsockopt(serverFd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(int))){ |
Was this helpful? React with 👍 or 👎 to provide feedback.
Debug
| //start editor | ||
| initEditor(); | ||
| editorSelectSyntaxHighlight("transfer"); | ||
| editorOpen(argv[1]); | ||
| enableRawMode(STDIN_FILENO); | ||
| editorSetStatusMessage( |
There was a problem hiding this comment.
🚩 Editor code after fgets loop is unreachable
The while (fgets(buffer, 1024, stdin)) loop at kilo.c:1362 reads from stdin until EOF. After EOF, the code at lines 1376-1385 attempts to start the editor, which also reads from stdin via editorProcessKeypress(STDIN_FILENO). Since stdin has already reached EOF, the editor will not be able to read any keypresses. The entire editor section (initEditor, editorOpen, enableRawMode, the main editor loop) is effectively dead code in the current flow. The architecture seems fundamentally broken — the client reads commands interactively, then tries to start an interactive editor on the same already-exhausted stdin.
(Refers to lines 1375-1385)
Was this helpful? React with 👍 or 👎 to provide feedback.
Summary
Copy of antirez/kilo#87 — "working server/client connection and copy file" by skylarscorca.
This PR adds server/client networking functionality to kilo, including:
server.cppimplementing a TCP server that can transfer files to connected clientsgetcommand in kilo to receive files from the server+245 −20 lines across 7 files changed.
Review & Testing Checklist for Human
getcommand in kilo)Notes
This is an exact copy of the original PR's commits cherry-picked onto this fork.
Link to Devin session: https://staging.itsdev.in/sessions/c4b105108b6444dc98e1bfaaa0914315
Requested by: @albert-cgai