💾 Archived View for gemi.dev › gemini-mailing-list › 000332.gmi captured on 2023-12-28 at 15:45:31. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-11-04)
-=-=-=-=-=-=-
G'day! Gemini, while simple, isn't quite that simple. All protocol commands and responses are over TLS connections, so doing a send/recv on a raw network socket will not work! I'm not 100% sure on the best or simplest way to get a TLS stack going in C, I've done some bits with OpenSSL, but it was not simple! Cheers -- Paul On 19/8/20 11:57 pm, - wrote: > Hello, > > I've started writing a client for Gemini protocol, but since I've never been writing networking programs, I find myself at the dead end at the moment. Please could someone help me? When I send a request and get a response, the only thing I have in response is "gemini://" and nothing else. The code is given below: > > #include <arpa/inet.h> > #include <locale.h> > #include <netdb.h> > #include <netinet/in.h> > #include <stdio.h> > #include <stdlib.h> > #include <string.h> > #include <sys/types.h> > #include <sys/socket.h> > #include <unistd.h> > > #define STATUS_CODE_INPUT 10 > #define STATUS_CODE_SENSITIVE_INPUT 11 > #define STATUS_CODE_SUCCESS 20 > #define STATUS_CODE_REDIRECT_TEMP 30 > #define STATUS_CODE_REDIRECT_PERM 31 > #define STATUS_CODE_TEMP_FAILURE 40 > #define STATUS_CODE_SERVER_UNAVAILABLE 41 > #define STATUS_CODE_CGI_ERROR 42 > #define STATUS_CODE_PROXY_ERROR 43 > #define STATUS_CODE_SLOW_DOWN 44 > #define STATUS_CODE_PERM_FAILURE 50 > #define STATUS_CODE_NOT_FOUND 51 > #define STATUS_CODE_GONE 52 > #define STATUS_CODE_PROXY_REQUEST_REFUSED 53 > #define STATUS_CODE_BAD_REQUEST 59 > #define STATUS_CODE_CLIENT_CERT_REQUIRED 60 > #define STATUS_CODE_CERT_NO_AUTH 61 > #define STATUS_CODE_CERT_NOT_VALID 62 > > #define GEMINI_PORT 1965 > > int main() { > char *locale; > locale = setlocale(LC_ALL, ""); > > int sockfd = socket(AF_INET, SOCK_STREAM, 0); > if (sockfd < 0) { > perror("socket"); > exit(1); > } > char *url = malloc(sizeof(char)*1024); > strcpy(url, "gemini://gemini.circumlunar.space/\r\n"); > char rec_buf[1029] = {0}; > struct hostent *host_entry; > host_entry = gethostbyname(url); > struct sockaddr_in addr; > addr.sin_family = AF_INET; > addr.sin_port = htons(GEMINI_PORT); > addr.sin_addr.s_addr = htonl(INADDR_ANY); > int opt = 1; > if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { > perror("setsockopt"); > exit(1); > } > if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { > perror("bind"); > exit(2); > } > if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { > perror("connect"); > exit(3); > } > send(sockfd, url, sizeof(url), 0); > recv(sockfd, rec_buf, sizeof(rec_buf), 0); > printf("%s\n", rec_buf); > close(sockfd); > shutdown(sockfd, SHUT_RDWR); > free(url); > return 0; > } > > -------------- next part -------------- A non-text attachment was scrubbed... Name: signature.asc Type: application/pgp-signature Size: 1003 bytes Desc: OpenPGP digital signature URL: <https://lists.orbitalfox.eu/archives/gemini/attachments/20200819/d18d a0bc/attachment.sig>
Hello, I've started writing a client for Gemini protocol, but since I've never been writing networking programs, I find myself at the dead end at the moment. Please could someone help me? When I send a request and get a response, the only thing I have in response is "gemini://" and nothing else. The code is given below: #include <arpa/inet.h> #include <locale.h> #include <netdb.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <unistd.h> #define STATUS_CODE_INPUT 10 #define STATUS_CODE_SENSITIVE_INPUT 11 #define STATUS_CODE_SUCCESS 20 #define STATUS_CODE_REDIRECT_TEMP 30 #define STATUS_CODE_REDIRECT_PERM 31 #define STATUS_CODE_TEMP_FAILURE 40 #define STATUS_CODE_SERVER_UNAVAILABLE 41 #define STATUS_CODE_CGI_ERROR 42 #define STATUS_CODE_PROXY_ERROR 43 #define STATUS_CODE_SLOW_DOWN 44 #define STATUS_CODE_PERM_FAILURE 50 #define STATUS_CODE_NOT_FOUND 51 #define STATUS_CODE_GONE 52 #define STATUS_CODE_PROXY_REQUEST_REFUSED 53 #define STATUS_CODE_BAD_REQUEST 59 #define STATUS_CODE_CLIENT_CERT_REQUIRED 60 #define STATUS_CODE_CERT_NO_AUTH 61 #define STATUS_CODE_CERT_NOT_VALID 62 #define GEMINI_PORT 1965 int main() { char *locale; locale = setlocale(LC_ALL, ""); int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("socket"); exit(1); } char *url = malloc(sizeof(char)*1024); strcpy(url, "gemini://gemini.circumlunar.space/\r\n"); char rec_buf[1029] = {0}; struct hostent *host_entry; host_entry = gethostbyname(url); struct sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(GEMINI_PORT); addr.sin_addr.s_addr = htonl(INADDR_ANY); int opt = 1; if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { perror("setsockopt"); exit(1); } if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("bind"); exit(2); } if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("connect"); exit(3); } send(sockfd, url, sizeof(url), 0); recv(sockfd, rec_buf, sizeof(rec_buf), 0); printf("%s\n", rec_buf); close(sockfd); shutdown(sockfd, SHUT_RDWR); free(url); return 0; } -- - <anridellal at yandex.ru>
This is something I had been tinkering with, before getting distracted onto something else(!). I found two examples of simple echo servers, one for GnuTLS and one OpenSSL. The code is here gemini://gemini.susa.net/c/ Both certainly compiled (I have binaries on disk), but I can't recall any more detail than that, so just sharing this as a pointer to the original poster. Kevin On Wed, 19 Aug 2020 at 12:36, Paul Warren <pwarren at pwarren.id.au> wrote: > > G'day! > > Gemini, while simple, isn't quite that simple. All protocol commands and > responses are over TLS connections, so doing a send/recv on a raw > network socket will not work! > > I'm not 100% sure on the best or simplest way to get a TLS stack going > in C, I've done some bits with OpenSSL, but it was not simple! > > Cheers > -- > Paul > > > > On 19/8/20 11:57 pm, - wrote: > > Hello, > > > > I've started writing a client for Gemini protocol, but since I've never been writing networking programs, I find myself at the dead end at the moment. Please could someone help me? When I send a request and get a response, the only thing I have in response is "gemini://" and nothing else. The code is given below: > > > > #include <arpa/inet.h> > > #include <locale.h> > > #include <netdb.h> > > #include <netinet/in.h> > > #include <stdio.h> > > #include <stdlib.h> > > #include <string.h> > > #include <sys/types.h> > > #include <sys/socket.h> > > #include <unistd.h> > > > > #define STATUS_CODE_INPUT 10 > > #define STATUS_CODE_SENSITIVE_INPUT 11 > > #define STATUS_CODE_SUCCESS 20 > > #define STATUS_CODE_REDIRECT_TEMP 30 > > #define STATUS_CODE_REDIRECT_PERM 31 > > #define STATUS_CODE_TEMP_FAILURE 40 > > #define STATUS_CODE_SERVER_UNAVAILABLE 41 > > #define STATUS_CODE_CGI_ERROR 42 > > #define STATUS_CODE_PROXY_ERROR 43 > > #define STATUS_CODE_SLOW_DOWN 44 > > #define STATUS_CODE_PERM_FAILURE 50 > > #define STATUS_CODE_NOT_FOUND 51 > > #define STATUS_CODE_GONE 52 > > #define STATUS_CODE_PROXY_REQUEST_REFUSED 53 > > #define STATUS_CODE_BAD_REQUEST 59 > > #define STATUS_CODE_CLIENT_CERT_REQUIRED 60 > > #define STATUS_CODE_CERT_NO_AUTH 61 > > #define STATUS_CODE_CERT_NOT_VALID 62 > > > > #define GEMINI_PORT 1965 > > > > int main() { > > char *locale; > > locale = setlocale(LC_ALL, ""); > > > > int sockfd = socket(AF_INET, SOCK_STREAM, 0); > > if (sockfd < 0) { > > perror("socket"); > > exit(1); > > } > > char *url = malloc(sizeof(char)*1024); > > strcpy(url, "gemini://gemini.circumlunar.space/\r\n"); > > char rec_buf[1029] = {0}; > > struct hostent *host_entry; > > host_entry = gethostbyname(url); > > struct sockaddr_in addr; > > addr.sin_family = AF_INET; > > addr.sin_port = htons(GEMINI_PORT); > > addr.sin_addr.s_addr = htonl(INADDR_ANY); > > int opt = 1; > > if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { > > perror("setsockopt"); > > exit(1); > > } > > if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { > > perror("bind"); > > exit(2); > > } > > if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { > > perror("connect"); > > exit(3); > > } > > send(sockfd, url, sizeof(url), 0); > > recv(sockfd, rec_buf, sizeof(rec_buf), 0); > > printf("%s\n", rec_buf); > > close(sockfd); > > shutdown(sockfd, SHUT_RDWR); > > free(url); > > return 0; > > } > > > > >
I think I misread some parts of specification. Thank you very much. On Wed, 19 Aug 2020 21:36:18 +1000 Paul Warren <pwarren at pwarren.id.au> wrote: > G'day! > > Gemini, while simple, isn't quite that simple. All protocol commands and > responses are over TLS connections, so doing a send/recv on a raw > network socket will not work! > > I'm not 100% sure on the best or simplest way to get a TLS stack going > in C, I've done some bits with OpenSSL, but it was not simple! > > Cheers > -- > Paul > > > > On 19/8/20 11:57 pm, - wrote: > > Hello, > > > > I've started writing a client for Gemini protocol, but since I've never been writing networking programs, I find myself at the dead end at the moment. Please could someone help me? When I send a request and get a response, the only thing I have in response is "gemini://" and nothing else. The code is given below: > > > > #include <arpa/inet.h> > > #include <locale.h> > > #include <netdb.h> > > #include <netinet/in.h> > > #include <stdio.h> > > #include <stdlib.h> > > #include <string.h> > > #include <sys/types.h> > > #include <sys/socket.h> > > #include <unistd.h> > > > > #define STATUS_CODE_INPUT 10 > > #define STATUS_CODE_SENSITIVE_INPUT 11 > > #define STATUS_CODE_SUCCESS 20 > > #define STATUS_CODE_REDIRECT_TEMP 30 > > #define STATUS_CODE_REDIRECT_PERM 31 > > #define STATUS_CODE_TEMP_FAILURE 40 > > #define STATUS_CODE_SERVER_UNAVAILABLE 41 > > #define STATUS_CODE_CGI_ERROR 42 > > #define STATUS_CODE_PROXY_ERROR 43 > > #define STATUS_CODE_SLOW_DOWN 44 > > #define STATUS_CODE_PERM_FAILURE 50 > > #define STATUS_CODE_NOT_FOUND 51 > > #define STATUS_CODE_GONE 52 > > #define STATUS_CODE_PROXY_REQUEST_REFUSED 53 > > #define STATUS_CODE_BAD_REQUEST 59 > > #define STATUS_CODE_CLIENT_CERT_REQUIRED 60 > > #define STATUS_CODE_CERT_NO_AUTH 61 > > #define STATUS_CODE_CERT_NOT_VALID 62 > > > > #define GEMINI_PORT 1965 > > > > int main() { > > char *locale; > > locale = setlocale(LC_ALL, ""); > > > > int sockfd = socket(AF_INET, SOCK_STREAM, 0); > > if (sockfd < 0) { > > perror("socket"); > > exit(1); > > } > > char *url = malloc(sizeof(char)*1024); > > strcpy(url, "gemini://gemini.circumlunar.space/\r\n"); > > char rec_buf[1029] = {0}; > > struct hostent *host_entry; > > host_entry = gethostbyname(url); > > struct sockaddr_in addr; > > addr.sin_family = AF_INET; > > addr.sin_port = htons(GEMINI_PORT); > > addr.sin_addr.s_addr = htonl(INADDR_ANY); > > int opt = 1; > > if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { > > perror("setsockopt"); > > exit(1); > > } > > if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { > > perror("bind"); > > exit(2); > > } > > if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { > > perror("connect"); > > exit(3); > > } > > send(sockfd, url, sizeof(url), 0); > > recv(sockfd, rec_buf, sizeof(rec_buf), 0); > > printf("%s\n", rec_buf); > > close(sockfd); > > shutdown(sockfd, SHUT_RDWR); > > free(url); > > return 0; > > } > > > > > -- - <anridellal at yandex.ru>
Thank you. I managed to make it work with LibreSSL's libtls: https://man.openbsd.org/tls_init.3 Sharing the code in case someone wants to take a look at an implementation (the code is far from perfection, but I'll fix it later): #include <arpa/inet.h> #include <locale.h> #include <netdb.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <tls.h> #include <unistd.h> #define STATUS_CODE_INPUT "10" #define STATUS_CODE_SENSITIVE_INPUT "11" #define STATUS_CODE_SUCCESS "20" #define STATUS_CODE_REDIRECT_TEMP "30" #define STATUS_CODE_REDIRECT_PERM "31" #define STATUS_CODE_TEMP_FAILURE "40" #define STATUS_CODE_SERVER_UNAVAILABLE "41" #define STATUS_CODE_CGI_ERROR "42" #define STATUS_CODE_PROXY_ERROR "43" #define STATUS_CODE_SLOW_DOWN "44" #define STATUS_CODE_PERM_FAILURE "50" #define STATUS_CODE_NOT_FOUND "51" #define STATUS_CODE_GONE "52" #define STATUS_CODE_PROXY_REQUEST_REFUSED "53" #define STATUS_CODE_BAD_REQUEST "59" #define STATUS_CODE_CLIENT_CERT_REQUIRED "60" #define STATUS_CODE_CERT_NO_AUTH "61" #define STATUS_CODE_CERT_NOT_VALID "62" #define GEMINI_PORT "1965" int main() { char *locale; locale = setlocale(LC_ALL, ""); tls_init(); struct tls_config *tlsconf = tls_config_new(); struct tls *client = tls_client(); tls_config_set_protocols(tlsconf, TLS_PROTOCOL_TLSv1_3); tls_configure(client, tlsconf); const char *hostname = "gemini.circumlunar.space"; char *url = malloc(sizeof(char)*1024); strcpy(url, "gemini://gemini.circumlunar.space/"); char rec_buf[1029]; int writebytes = sprintf(url, "%s\r\n", url); tls_connect(client, hostname, GEMINI_PORT); while (writebytes > 0) { ssize_t outbytes; outbytes = tls_write(client, url, (size_t)writebytes); if (outbytes == TLS_WANT_POLLIN || outbytes == TLS_WANT_POLLOUT) continue; if (outbytes == -1) { perror("tls_write"); } url += outbytes; writebytes -= outbytes; } // read header tls_read(client, rec_buf, sizeof(rec_buf)); printf("%s\n", rec_buf); char status_code[3]; strncpy(status_code, rec_buf, 2); if (strcmp(status_code, STATUS_CODE_SUCCESS) == 0) { writebytes = tls_read(client, rec_buf, (size_t)sizeof(rec_buf)); printf("%d\n", writebytes); while (writebytes > 0) { printf(rec_buf); writebytes = tls_read(client, rec_buf, (size_t)writebytes); printf("\n%d\n", writebytes); } printf("\r\n"); } tls_close(client); tls_free(client); return 0; } On Wed, 19 Aug 2020 15:55:00 +0100 Kevin Sangeelee <kevin at susa.net> wrote: > This is something I had been tinkering with, before getting distracted > onto something else(!). I found two examples of simple echo servers, > one for GnuTLS and one OpenSSL. The code is here > > gemini://gemini.susa.net/c/ > > Both certainly compiled (I have binaries on disk), but I can't recall > any more detail than that, so just sharing this as a pointer to the > original poster. > > Kevin > > On Wed, 19 Aug 2020 at 12:36, Paul Warren <pwarren at pwarren.id.au> wrote: > > > > G'day! > > > > Gemini, while simple, isn't quite that simple. All protocol commands and > > responses are over TLS connections, so doing a send/recv on a raw > > network socket will not work! > > > > I'm not 100% sure on the best or simplest way to get a TLS stack going > > in C, I've done some bits with OpenSSL, but it was not simple! > > > > Cheers > > -- > > Paul > > > > > > > > On 19/8/20 11:57 pm, - wrote: > > > Hello, > > > > > > I've started writing a client for Gemini protocol, but since I've never been writing networking programs, I find myself at the dead end at the moment. Please could someone help me? When I send a request and get a response, the only thing I have in response is "gemini://" and nothing else. The code is given below: > > > > > > #include <arpa/inet.h> > > > #include <locale.h> > > > #include <netdb.h> > > > #include <netinet/in.h> > > > #include <stdio.h> > > > #include <stdlib.h> > > > #include <string.h> > > > #include <sys/types.h> > > > #include <sys/socket.h> > > > #include <unistd.h> > > > > > > #define STATUS_CODE_INPUT 10 > > > #define STATUS_CODE_SENSITIVE_INPUT 11 > > > #define STATUS_CODE_SUCCESS 20 > > > #define STATUS_CODE_REDIRECT_TEMP 30 > > > #define STATUS_CODE_REDIRECT_PERM 31 > > > #define STATUS_CODE_TEMP_FAILURE 40 > > > #define STATUS_CODE_SERVER_UNAVAILABLE 41 > > > #define STATUS_CODE_CGI_ERROR 42 > > > #define STATUS_CODE_PROXY_ERROR 43 > > > #define STATUS_CODE_SLOW_DOWN 44 > > > #define STATUS_CODE_PERM_FAILURE 50 > > > #define STATUS_CODE_NOT_FOUND 51 > > > #define STATUS_CODE_GONE 52 > > > #define STATUS_CODE_PROXY_REQUEST_REFUSED 53 > > > #define STATUS_CODE_BAD_REQUEST 59 > > > #define STATUS_CODE_CLIENT_CERT_REQUIRED 60 > > > #define STATUS_CODE_CERT_NO_AUTH 61 > > > #define STATUS_CODE_CERT_NOT_VALID 62 > > > > > > #define GEMINI_PORT 1965 > > > > > > int main() { > > > char *locale; > > > locale = setlocale(LC_ALL, ""); > > > > > > int sockfd = socket(AF_INET, SOCK_STREAM, 0); > > > if (sockfd < 0) { > > > perror("socket"); > > > exit(1); > > > } > > > char *url = malloc(sizeof(char)*1024); > > > strcpy(url, "gemini://gemini.circumlunar.space/\r\n"); > > > char rec_buf[1029] = {0}; > > > struct hostent *host_entry; > > > host_entry = gethostbyname(url); > > > struct sockaddr_in addr; > > > addr.sin_family = AF_INET; > > > addr.sin_port = htons(GEMINI_PORT); > > > addr.sin_addr.s_addr = htonl(INADDR_ANY); > > > int opt = 1; > > > if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { > > > perror("setsockopt"); > > > exit(1); > > > } > > > if (bind(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { > > > perror("bind"); > > > exit(2); > > > } > > > if (connect(sockfd, (struct sockaddr *)&addr, sizeof(addr)) < 0) { > > > perror("connect"); > > > exit(3); > > > } > > > send(sockfd, url, sizeof(url), 0); > > > recv(sockfd, rec_buf, sizeof(rec_buf), 0); > > > printf("%s\n", rec_buf); > > > close(sockfd); > > > shutdown(sockfd, SHUT_RDWR); > > > free(url); > > > return 0; > > > } > > > > > > > > -- - <anridellal at yandex.ru>
---