:(before "End Types") struct socket_t { int fd; sockaddr_in addr; bool polled; socket_t() { fd = 0; polled = false; bzero(&addr, sizeof(addr)); } }; :(before "End Primitive Recipe Declarations") _OPEN_CLIENT_SOCKET, :(before "End Primitive Recipe Numbers") put(Recipe_ordinal, "$open-client-socket", _OPEN_CLIENT_SOCKET); :(before "End Primitive Recipe Checks") case _OPEN_CLIENT_SOCKET: { if (SIZE(inst.ingredients) != 2) { raise << maybe(get(Recipe, r).name) << "'$open-client-socket' requires exactly two ingredients, but got '" << to_original_string(inst) << "'\n" << end(); break; } if (!is_mu_text(inst.ingredients.at(0))) { raise << maybe(get(Recipe, r).name) << "first ingredient of '$open-client-socket' should be text (the hostname), but got '" << to_string(inst.ingredients.at(0)) << "'\n" << end(); break; } if (!is_mu_number(inst.ingredients.at(1))) { raise << maybe(get(Recipe, r).name) << "second ingredient of '$open-client-socket' should be a number (the port of the hostname to connect to), but got '" << to_string(inst.ingredients.at(1)) << "'\n" << end(); break; } if (SIZE(inst.products) != 1) { raise << maybe(get(Recipe, r).name) << "'$open-client-socket' requires exactly one product, but got '" << to_original_string(inst) << "'\n" << end(); break; } if (!is_mu_number(inst.products.at(0))) { raise << maybe(get(Recipe, r).name) << "first product of '$open-client-socket' should be a number (socket handle), but got '" << to_string(inst.products.at(0)) << "'\n" << end(); break; } break; } :(before "End Primitive Recipe Implementations") case _OPEN_CLIENT_SOCKET: { string host = read_mu_text(ingredients.at(0).at(/*skip alloc id*/1)); int port = ingredients.at(1).at(0); socket_t* client = client_socket(host, port); products.resize(1); if (client->fd < 0) { // error delete client; products.at(0).push_back(0); break; } long long int result = reinterpret_cast(client); products.at(0).push_back(static_cast(result)); break; } :(code) socket_t* client_socket(const string& host, int port) { socket_t* result = new socket_t; result->fd = socket(AF_INET, SOCK_STREAM, 0); if (result->fd < 0) { raise << "Failed to create socket.\n" << end(); return result; } result->addr.sin_family = AF_INET; hostent* tmp = gethostbyname(host.c_str()); bcopy(tmp->h_addr, reinterpret_cast(&result->addr.sin_addr.s_addr), tmp->h_length); result->addr.sin_port = htons(port); if (connect(result->fd, reinterpret_cast(&result->addr), sizeof(result->addr)) < 0) { close(result->fd); result->fd = -1; raise << "Failed to connect to " << host << ':' << port << '\n' << end(); } return result; } :(before "End Primitive Recipe Declarations") _OPEN_SERVER_SOCKET, :(before "End Primitive Recipe Numbers") put(Recipe_ordinal, "$open-server-socket", _OPEN_SERVER_SOCKET); :(before "End Primitive Recipe Checks") case _OPEN_SERVER_SOCKET: { if (SIZE(inst.ingredients) != 1) { raise << maybe(get(Recipe, r).name) << "'$open-server-socket' requires exactly one ingredient (the port to listen for requests on), but got '" << to_original_string(inst) << "'\n" << end(); break; } if (!is_mu_number(inst.ingredients.at(0))) { raise << maybe(get(Recipe, r).name) << "first ingredient of '$open-server-socket' should be a number, but got '" << to_string(inst.ingredients.at(0)) << "'\n" << end(); break; } if (SIZE(inst.products) != 1) { raise << maybe(get(Recipe, r).name) << "'$open-server-socket' requires exactly one product, but got '" << to_original_string(inst) << "'\n" << end(); break; } if (!is_mu_number(inst.products.at(0))) { raise << maybe(get(Recipe, r).name) << "first product of '$open-server-socket' should be a number (file handle), but got '" << to_string(inst.products.at(0)) << "'\n" << end(); break; } break; } :(before "End Primitive Recipe Implementations") case _OPEN_SERVER_SOCKET: { int port = ingredients.at(0).at(0); socket_t* server = server_socket(port); products.resize(1); if (server->fd < 0) { delete server; products.at(0).push_back(0); break; } long long int result = reinterpret_cast(server); products.at(0).push_back(static_cast(result)); break; } :(code) socket_t* server_socket(int port) { socket_t* result = new socket_t; result->fd = socket(AF_INET, SOCK_STREAM, 0); if (result->fd < 0) { raise << "Failed to create server socket.\n" << end(); return result; } int dummy = 0; setsockopt(result->fd, SOL_SOCKET, SO_REUSEADDR, &dummy, sizeof(dummy)); result->addr.sin_family = AF_INET; result->addr.sin_addr.s_addr = Current_scenario ? htonl(INADDR_LOOPBACK) : INADDR_ANY; // run tests without running afoul of any firewall result->addr.sin_port = htons(port); if (bind(result->fd, reinterpret_cast(&result->addr), sizeof(result->addr)) >= 0) {
# Various knobs for translating SubX programs using SubX.

== data

# largest segment that can be translated
Segment-size:
  0x80000/imm32/512KB

# maximum size of input textual stream (spanning all segments)
Input-size:
  0x100000/imm32/1MB

# number of labels we can translate to addresses
Max-labels:
  0x10000/imm32/4K-labels/64KB
(out.str().c_str()); //? } products.at(0).push_back(c); products.at(1).push_back(/*found*/true); products.at(2).push_back(/*eof*/bytes_read <= 0); products.at(3).push_back(error_code); break; } :(before "End Primitive Recipe Declarations") _WRITE_TO_SOCKET, :(before "End Primitive Recipe Numbers") put(Recipe_ordinal, "$write-to-socket", _WRITE_TO_SOCKET); :(before "End Primitive Recipe Checks") case _WRITE_TO_SOCKET: { if (SIZE(inst.ingredients) != 2) { raise << maybe(get(Recipe, r).name) << "'$write-to-socket' requires exactly two ingredient, but got '" << to_original_string(inst) << "'\n" << end(); break; } break; } :(before "End Primitive Recipe Implementations") case _WRITE_TO_SOCKET: { long long int x = static_cast(ingredients.at(0).at(0)); socket_t* socket = reinterpret_cast(x); // write just one character at a time to the socket long long int y = static_cast(ingredients.at(1).at(0)); char c = static_cast(y); if (write(socket->fd, &c, 1) != 1) { raise << maybe(current_recipe_name()) << "failed to write to socket\n" << end(); exit(0); } products.resize(1); products.at(0).push_back(ingredients.at(0).at(0)); break; } :(before "End Primitive Recipe Declarations") _CLOSE_SOCKET, :(before "End Primitive Recipe Numbers") put(Recipe_ordinal, "$close-socket", _CLOSE_SOCKET); :(before "End Primitive Recipe Checks") case _CLOSE_SOCKET: { if (SIZE(inst.ingredients) != 1) { raise << maybe(get(Recipe, r).name) << "'$close-socket' requires exactly two ingredient, but got '" << to_original_string(inst) << "'\n" << end(); break; } if (!is_mu_number(inst.ingredients.at(0))) { raise << maybe(get(Recipe, r).name) << "first ingredient of '$close-socket' should be a number, but got '" << to_string(inst.ingredients.at(0)) << "'\n" << end(); break; } if (SIZE(inst.products) != 1) { raise << maybe(get(Recipe, r).name) << "'$close-socket' requires exactly one product, but got '" << to_original_string(inst) << "'\n" << end(); break; } if (inst.products.at(0).name != inst.ingredients.at(0).name) { raise << maybe(get(Recipe, r).name) << "product of '$close-socket' must be first ingredient '" << inst.ingredients.at(0).original_string << "', but got '" << inst.products.at(0).original_string << "'\n" << end(); break; } break; } :(before "End Primitive Recipe Implementations") case _CLOSE_SOCKET: { long long int x = static_cast(ingredients.at(0).at(0)); socket_t* socket = reinterpret_cast(x); close(socket->fd); delete socket; products.resize(1); products.at(0).push_back(0); // make sure we can't reuse the socket break; } :(before "End Includes") #include #include #include #include #include