13 #include <sys/socket.h>
14 #include <arpa/inet.h>
25 static KrkClass * SocketError = NULL;
26 static KrkClass * SocketClass = NULL;
37 #define IS_socket(o) (krk_isInstanceOf(o,SocketClass))
38 #define AS_socket(o) ((struct socket*)AS_OBJECT(o))
39 #define CURRENT_CTYPE struct socket *
40 #define CURRENT_NAME self
42 KRK_Method(
socket,__init__) {
43 METHOD_TAKES_AT_MOST(3);
46 int type = SOCK_STREAM;
50 (
const char *[]){
"family",
"type",
"proto"},
51 &family, &type, &proto)) {
55 int result =
socket(family,type,proto);
61 self->sockfd = result;
62 self->family = family;
69 static char * _af_name(
int afval) {
72 case AF_INET:
return "AF_INET";
74 case AF_INET6:
return "AF_INET6";
77 case AF_UNIX:
return "AF_UNIX";
80 snprintf(tmp,30,
"%d",afval);
85 static char * _sock_type(
int type) {
88 case SOCK_STREAM:
return "SOCK_STREAM";
89 case SOCK_DGRAM:
return "SOCK_DGRAM";
91 case SOCK_RAW:
return "SOCK_RAW";
94 snprintf(tmp,30,
"%d",type);
99 KRK_Method(
socket,__repr__) {
101 size_t len = snprintf(tmp, 4096,
"<socket.socket fd=%d, family=%s, type=%s, proto=%d>",
102 self->sockfd, _af_name(self->family), _sock_type(self->type), self->proto);
106 static int socket_parse_address(
struct socket *
self,
KrkValue address,
struct sockaddr_storage *sock_addr, socklen_t *sock_size) {
107 if (self->family == AF_INET) {
109 if (!IS_tuple(address)) {
113 KrkTuple * addr = AS_TUPLE(address);
128 struct sockaddr_in * sin = (
struct sockaddr_in*)sock_addr;
129 *sock_size =
sizeof(
struct sockaddr_in);
130 sin->sin_family = AF_INET;
132 sin->sin_addr.s_addr = INADDR_ANY;
135 struct addrinfo *result;
136 struct addrinfo *res;
137 int error = getaddrinfo(AS_CSTRING(addr->
values.
values[0]), NULL, NULL, &result);
146 if (res->ai_family == AF_INET) {
148 *sock_size = res->ai_addrlen;
149 memcpy(sock_addr, res->ai_addr, *sock_size);
155 freeaddrinfo(result);
162 struct sockaddr_in * sin = (
struct sockaddr_in*)sock_addr;
163 sin->sin_family = AF_INET;
169 }
else if (self->family == AF_INET6) {
171 if (!IS_tuple(address)) {
175 KrkTuple * addr = AS_TUPLE(address);
190 struct sockaddr_in6 * sin = (
struct sockaddr_in6*)sock_addr;
191 *sock_size =
sizeof(
struct sockaddr_in6);
192 sin->sin6_family = AF_INET6;
194 sin->sin6_addr = in6addr_any;
197 struct addrinfo *result;
198 struct addrinfo *res;
199 int error = getaddrinfo(AS_CSTRING(addr->
values.
values[0]), NULL, NULL, &result);
208 if (res->ai_family == AF_INET6) {
210 *sock_size = res->ai_addrlen;
211 memcpy(sock_addr, res->ai_addr, *sock_size);
217 freeaddrinfo(result);
224 struct sockaddr_in6 * sin = (
struct sockaddr_in6*)sock_addr;
225 sin->sin6_family = AF_INET6;
232 }
else if (self->family == AF_UNIX) {
233 if (!IS_str(address)) {
234 krk_runtimeError(
vm.exceptions->typeError,
"Address should be str, not '%T'", address);
238 if (AS_STRING(address)->length > 107) {
243 struct sockaddr_un * sun = (
struct sockaddr_un*)sock_addr;
244 *sock_size =
sizeof(
struct sockaddr_un);
245 sun->sun_family = AF_UNIX;
246 memcpy(sun->sun_path, AS_CSTRING(address), AS_STRING(address)->length + 1);
257 KRK_Method(
socket,connect) {
258 METHOD_TAKES_EXACTLY(1);
260 struct sockaddr_storage sock_addr;
261 socklen_t sock_size = 0;
264 int parseResult = socket_parse_address(
self, argv[1], &sock_addr, &sock_size);
271 int result = connect(self->sockfd, (
struct sockaddr*)&sock_addr, sock_size);
281 METHOD_TAKES_EXACTLY(1);
283 struct sockaddr_storage sock_addr;
284 socklen_t sock_size = 0;
287 int parseResult = socket_parse_address(
self, argv[1], &sock_addr, &sock_size);
294 int result = bind(self->sockfd, (
struct sockaddr*)&sock_addr, sock_size);
303 KRK_Method(
socket,listen) {
304 METHOD_TAKES_AT_MOST(1);
307 CHECK_ARG(1,
int,krk_integer_type,val);
308 backlog = val >= 0 ? val : 0;
311 int result = listen(self->sockfd, backlog);
319 KRK_Method(
socket,accept) {
320 struct sockaddr_storage addr;
323 int result = accept(self->sockfd, (
struct sockaddr*)&addr, &addrlen);
335 out->sockfd = result;
336 out->family =
self->family;
337 out->type =
self->type;
338 out->proto =
self->proto;
345 if (self->family == AF_INET) {
349 char hostname[NI_MAXHOST] =
"";
350 getnameinfo((
struct sockaddr*)&addr, addrlen, hostname, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
354 addrTuple->
values.
values[1] = INTEGER_VAL(htons(((
struct sockaddr_in*)&addr)->sin_port));
357 }
else if (self->family == AF_INET6) {
361 char hostname[NI_MAXHOST] =
"";
362 getnameinfo((
struct sockaddr*)&addr, addrlen, hostname, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
366 addrTuple->
values.
values[1] = INTEGER_VAL(htons(((
struct sockaddr_in6*)&addr)->sin6_port));
370 }
else if (self->family == AF_UNIX) {
385 KRK_Method(
socket,shutdown) {
386 METHOD_TAKES_EXACTLY(1);
387 CHECK_ARG(1,
int,krk_integer_type,how);
389 int result = shutdown(self->sockfd, how);
399 METHOD_TAKES_AT_LEAST(1);
400 METHOD_TAKES_AT_MOST(2);
401 CHECK_ARG(1,
int,krk_integer_type,bufsize);
404 CHECK_ARG(2,
int,krk_integer_type,_flags);
408 void * buf = malloc(bufsize);
409 ssize_t result = recv(self->sockfd, buf, bufsize, flags);
417 return OBJECT_VAL(out);
421 METHOD_TAKES_AT_LEAST(1);
422 METHOD_TAKES_AT_MOST(2);
426 CHECK_ARG(2,
int,krk_integer_type,_flags);
430 ssize_t result = send(self->sockfd, (
void*)buf->bytes, buf->length, flags);
435 return INTEGER_VAL(result);
438 KRK_Method(
socket,sendto) {
439 METHOD_TAKES_AT_LEAST(1);
440 METHOD_TAKES_AT_MOST(3);
444 CHECK_ARG(2,
int,krk_integer_type,_flags);
448 struct sockaddr_storage sock_addr;
449 socklen_t sock_size = 0;
452 int parseResult = socket_parse_address(
self, argv[argc-1], &sock_addr, &sock_size);
459 ssize_t result = sendto(self->sockfd, (
void*)buf->bytes, buf->length, flags, (
struct sockaddr*)&sock_addr, sock_size);
464 return INTEGER_VAL(result);
468 KRK_Method(
socket,fileno) {
469 return INTEGER_VAL(self->sockfd);
472 KRK_Method(
socket,setsockopt) {
473 METHOD_TAKES_EXACTLY(3);
474 CHECK_ARG(1,
int,krk_integer_type,level);
475 CHECK_ARG(2,
int,krk_integer_type,optname);
479 if (IS_INTEGER(argv[3])) {
480 int val = AS_INTEGER(argv[3]);
481 result = setsockopt(self->sockfd, level, optname, (
void*)&val,
sizeof(
int));
482 }
else if (IS_BYTES(argv[3])) {
483 result = setsockopt(self->sockfd, level, optname, (
void*)AS_BYTES(argv[3])->bytes, AS_BYTES(argv[3])->length);
485 return TYPE_ERROR(
int or bytes,argv[3]);
495 KRK_Function(htons) {
496 FUNCTION_TAKES_EXACTLY(1);
497 CHECK_ARG(0,
int,krk_integer_type,value);
498 return INTEGER_VAL(htons(value));
501 KRK_Method(
socket,family) {
502 if (argc > 1)
return krk_runtimeError(
vm.exceptions->attributeError,
"readonly attribute");
503 return INTEGER_VAL(self->family);
507 if (argc > 1)
return krk_runtimeError(
vm.exceptions->attributeError,
"readonly attribute");
508 return INTEGER_VAL(self->type);
511 KRK_Method(
socket,proto) {
512 if (argc > 1)
return krk_runtimeError(
vm.exceptions->attributeError,
"readonly attribute");
513 return INTEGER_VAL(self->proto);
517 KRK_DOC(module,
"Lightweight wrapper around the standard Berkeley sockets interface.");
522 "@brief Create a socket object.\n"
523 "@arguments family=AF_INET,type=SOCK_STREAM,proto=0\n\n"
524 "Creates a new socket object for the given address family and type.");
525 BIND_METHOD(
socket,__repr__);
527 "@brief Bind a socket to an address.\n"
528 "@arguments address\n\n"
529 "The format of @p address varies by address family. For @c AF_INET, @p address should be a "
530 "two-tuple of a string domain name and integer port number.");
532 "@brief Set a bound socket to listen.\n"
533 "@arguments backlog=0\n\n"
534 "Begin listening on a bound socket, keeping @p backlog connections in a queue.");
536 "@brief Accept a connection on a listening socket.\n\n"
537 "Accepts one connection and returns a two-tuple with a new socket object and "
538 "the address of the remote host.");
540 "@brief Connect a socket to a remote endpoint.\n"
541 "@arguments address\n\n"
542 "As with @ref socket_bind, the format of @p address varies.");
544 "@brief Shut down an active socket.\n"
546 "Gracefully closes an open socket.");
548 "@brief Receive data from a connected socket.\n"
549 "@arguments bufsize,[flags]\n\n"
550 "Receive up to @p bufsize bytes of data, which is returned as a @ref bytes object.");
552 "@brief Send data to a connected socket.\n"
553 "@arguments buf,[flags]\n\n"
554 "Send the data in the @ref bytes object @p buf to the socket. Returns the number "
555 "of bytes written to the socket.");
557 "@brief Send data to an socket with a particular destination.\n"
558 "@arguments buf,[flags],addr\n\n"
559 "Send the data in the @ref bytes object @p buf to the socket. Returns the number "
560 "of bytes written to the socket.");
562 "@brief Get the file descriptor number for the underlying socket.");
564 "@brief Set socket options.\n"
565 "@arguments level,optname,value\n\n"
566 "@p level and @p optname should be integer values defined by @c SOL and @c SO options. "
567 "@p value must be either an @ref int or a @ref bytes object.");
575 BIND_FUNC(module, htons);
578 #define SOCK_CONST(o) krk_attachNamedValue(&module->fields, #o, INTEGER_VAL(o));
588 SOCK_CONST(AF_INET6);
595 SOCK_CONST(SOCK_STREAM);
596 SOCK_CONST(SOCK_DGRAM);
598 SOCK_CONST(SOCK_RAW);
603 SOCK_CONST(SOCK_NONBLOCK);
606 SOCK_CONST(SOCK_CLOEXEC);
612 SOCK_CONST(SHUT_RDWR);
615 SOCK_CONST(SOL_SOCKET);
617 SOCK_CONST(SO_REUSEADDR);
619 krk_makeClass(module, &SocketError,
"SocketError",
vm.exceptions->baseException);
620 KRK_DOC(SocketError,
"Raised on faults from socket functions.");
KrkValue krk_runtimeError(KrkClass *type, const char *fmt,...)
Produce and raise an exception with a formatted message.
Immutable sequence of bytes.
KrkBytes * krk_newBytes(size_t length, uint8_t *source)
Create a new byte array.
size_t allocSize
Size to allocate when creating instances of this class.
KrkClass * krk_makeClass(KrkInstance *module, KrkClass **_class, const char *name, KrkClass *base)
Convenience function for creating new types.
void krk_finalizeClass(KrkClass *_class)
Finalize a class by collecting pointers to core methods.
KrkInstance * krk_newInstance(KrkClass *_class)
Create a new instance of the given class.
KrkString * krk_copyString(const char *chars, size_t length)
Obtain a string object representation of the given C string.
Immutable sequence of arbitrary values.
KrkValueArray values
Stores the length, capacity, and actual values of the tuple.
KrkTuple * krk_newTuple(size_t length)
Create a new tuple.
Stack reference or primative value.
Utilities for creating native bindings.
#define krk_parseArgs(f, n,...)
Parse arguments to a function while accepting keyword arguments.
#define KRK_DOC(thing, text)
Attach documentation to a thing of various types.
Core API for the bytecode virtual machine.
krk_threadLocal KrkThreadState krk_currentThread
Thread-local VM state.
#define vm
Convenience macro for namespacing.
KrkValue krk_pop(void)
Pop the top of the stack.
void krk_push(KrkValue value)
Push a stack value.
KrkValue krk_peek(int distance)
Peek down from the top of the stack.