/* rxrpc.c: description * * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ #include #include #include #include #include #include #include #include #include #define VLGETENTRYBYID 503 /* AFS Get Cache Entry By ID operation ID */ #define VLGETENTRYBYNAME 504 /* AFS Get Cache Entry By Name operation ID */ #define VLPROBE 514 /* AFS Probe Volume Location Service operation ID */ struct sockaddr_rxrpc { sa_family_t srx_family; /* address family */ unsigned short srx_service; /* service desired */ unsigned short transport_type; /* type of transport socket (SOCK_DGRAM) */ unsigned short transport_len; /* length of transport address */ union { sa_family_t family; /* transport address family */ struct sockaddr_in sin; /* IPv4 transport address */ struct sockaddr_in6 sin6; /* IPv6 transport address */ } transport; }; #define AF_RXRPC 33 #define PF_RXRPC AF_RXRPC #define SOL_RXRPC 272 #define RXRPC_USER_CALL_ID 1 /* User call ID specifier */ #define RXRPC_ABORT 2 /* Abort request / notification */ #define RXRPC_ACK 3 /* [Server] RPC op final ACK received */ #define RXRPC_RESPONSE 4 /* [Server] security response received */ #define RXRPC_NET_ERROR 5 /* network error received */ #define RXRPC_BUSY 6 /* server busy received */ #define RXRPC_LOCAL_ERROR 7 /* local error generated */ #define RXRPC_PREPARE_CALL_SLOT 8 /* Propose user call ID specifier for next call */ #define RXRPC_SECURITY_KEY 1 /* [clnt] set client security key */ #define RXRPC_SECURITY_KEYRING 2 /* [srvr] set ring of server security keys */ #define RXRPC_EXCLUSIVE_CONNECTION 3 /* [clnt] use exclusive RxRPC connection */ #define RXRPC_MIN_SECURITY_LEVEL 4 /* minimum security level */ #define RXRPC_SECURITY_PLAIN 0 /* plain secure-checksummed packets only */ #define RXRPC_SECURITY_AUTH 1 /* authenticated packets */ #define RXRPC_SECURITY_ENCRYPT 2 /* encrypted packets */ #define OSERROR(X, Y) do { if ((long)(X) == -1) { perror(Y); exit(1); } } while(0) static const unsigned char local_addr[4] = { 0, 0, 0, 0 }; static const unsigned char remote_addr[4] = { 172, 16, 18, 91 }; //static const unsigned char remote_addr[4] = { 192, 168, 2, 129 }; #define RXRPC_ADD_CALLID(control, ctrllen, id) \ do { \ struct cmsghdr *__cmsg; \ __cmsg = (void *)(control) + (ctrllen); \ __cmsg->cmsg_len = CMSG_LEN(sizeof(unsigned long)); \ __cmsg->cmsg_level = SOL_RXRPC; \ __cmsg->cmsg_type = RXRPC_USER_CALL_ID; \ *(unsigned long *)CMSG_DATA(__cmsg) = (id); \ (ctrllen) += __cmsg->cmsg_len; \ \ } while (0) #define RXRPC_ADD_ABORT(control, ctrllen, abort_code) \ do { \ struct cmsghdr *__cmsg; \ __cmsg = (void *)(control) + (ctrllen); \ __cmsg->cmsg_len = CMSG_LEN(sizeof(unsigned int)); \ __cmsg->cmsg_level = SOL_RXRPC; \ __cmsg->cmsg_type = RXRPC_ABORT; \ *(unsigned int *)CMSG_DATA(__cmsg) = (abort_code); \ (ctrllen) += __cmsg->cmsg_len; \ \ } while (0) char cell[] = "afs@CAMBRIDGE.REDHAT.COM"; char vlname[] = "root.afs"; /*****************************************************************************/ /* * dump the control messages */ static void dump_cmsg(struct msghdr *msg) { struct cmsghdr *cmsg; unsigned long user_id; unsigned char *p; int abort_code; int n; for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) { n = cmsg->cmsg_len - CMSG_ALIGN(sizeof(*cmsg)); p = CMSG_DATA(cmsg); printf("CMSG: %zu: ", cmsg->cmsg_len); if (cmsg->cmsg_level == SOL_RXRPC) { switch (cmsg->cmsg_type) { case RXRPC_USER_CALL_ID: printf("RXRPC_USER_CALL_ID: "); if (n != sizeof(user_id)) goto dump_data; memcpy(&user_id, p, sizeof(user_id)); printf("%lx\n", user_id); continue; case RXRPC_ABORT: printf("RXRPC_ABORT: "); if (n != sizeof(abort_code)) goto dump_data; memcpy(&abort_code, p, sizeof(abort_code)); printf("%d\n", abort_code); continue; case RXRPC_ACK: printf("RXRPC_ACK"); if (n != 0) goto dump_data_colon; goto print_nl; case RXRPC_RESPONSE: printf("RXRPC_RESPONSE"); if (n != 0) goto dump_data_colon; goto print_nl; case RXRPC_NET_ERROR: printf("RXRPC_NET_ERROR: "); if (n != sizeof(abort_code)) goto dump_data; memcpy(&abort_code, p, sizeof(abort_code)); printf("%s\n", strerror(abort_code)); continue; case RXRPC_BUSY: printf("RXRPC_BUSY"); if (n != 0) goto dump_data_colon; goto print_nl; case RXRPC_LOCAL_ERROR: printf("RXRPC_LOCAL_ERROR: "); if (n != sizeof(abort_code)) goto dump_data; memcpy(&abort_code, p, sizeof(abort_code)); printf("%s\n", strerror(abort_code)); continue; default: break; } } printf("l=%d t=%d", cmsg->cmsg_level, cmsg->cmsg_type); dump_data_colon: printf(": "); dump_data: printf("{"); for (; n > 0; n--, p++) printf("%02x", *p); print_nl: printf("}\n"); } } /*****************************************************************************/ /* * */ int main(int argc, char *argv[]) { struct sockaddr_rxrpc srx; unsigned char buffer[4096], control[4096], control2[4096]; struct msghdr msg, msg2; struct iovec iov[3], iov2[3]; unsigned int padding, param[2], sec; size_t ctrllen, ctrllen2; int client, ret, ioc, ioc2, loop; client = socket(AF_RXRPC, SOCK_DGRAM, PF_INET); OSERROR(client, "socket"); /* set the security we want to use */ sec = RXRPC_SECURITY_PLAIN; ret = setsockopt(client, SOL_RXRPC, RXRPC_MIN_SECURITY_LEVEL, &sec, sizeof(sec)); ret = setsockopt(client, SOL_RXRPC, RXRPC_SECURITY_KEY, cell, strlen(cell)); OSERROR(ret, "key"); /* bind an address to the local endpoint */ srx.srx_family = AF_RXRPC; srx.srx_service = 1; /* it's a client */ srx.transport_type = SOCK_DGRAM; srx.transport_len = sizeof(srx.transport.sin); srx.transport.sin.sin_family = AF_INET; srx.transport.sin.sin_port = htons(7001); memcpy(&srx.transport.sin.sin_addr, &local_addr, 4); ret = bind(client, (struct sockaddr *) &srx, sizeof(srx)); OSERROR(client, "bind"); //system("netstat -ua"); /* connect to the remote server */ srx.srx_family = AF_RXRPC; srx.srx_service = 52; srx.transport_type = SOCK_DGRAM; srx.transport_len = sizeof(srx.transport.sin); srx.transport.sin.sin_family = AF_INET; srx.transport.sin.sin_port = htons(7003); memcpy(&srx.transport.sin.sin_addr, &remote_addr, 4); #if 0 ret = connect(client, (struct sockaddr *) &srx, sizeof(srx)); OSERROR(ret, "connect"); #endif /* request an operation */ ctrllen = 0; RXRPC_ADD_CALLID(control, ctrllen, 0x12345); ctrllen2 = 0; RXRPC_ADD_CALLID(control2, ctrllen2, 0x6543); #if 1 iov[0].iov_len = sizeof(param); iov[0].iov_base = param; iov[1].iov_len = sizeof(vlname) - 1; iov[1].iov_base = vlname; padding = 0; iov[2].iov_len = 4 - (iov[1].iov_len & 3); iov[2].iov_base = &padding; ioc = (iov[2].iov_len > 0) ? 3 : 2; param[0] = htonl(VLGETENTRYBYNAME); param[1] = htonl(iov[1].iov_len); iov2[0].iov_len = sizeof(param); iov2[0].iov_base = param; iov2[1].iov_len = sizeof(vlname) - 1; iov2[1].iov_base = vlname; iov2[2].iov_len = 4 - (iov2[1].iov_len & 3); iov2[2].iov_base = &padding; ioc2 = (iov2[2].iov_len > 0) ? 3 : 2; #else iov[0].iov_len = sizeof(param); iov[0].iov_base = param; char filename[] = "/usr/share/doc/lsof-4.77/00FAQ"; //char filename[] = "/usr/share/doc/lsof-4.77/00MANIFEST"; iov[1].iov_len = sizeof(filename) - 1; iov[1].iov_base = filename; padding = 0; iov[2].iov_len = 4 - (iov[1].iov_len & 3); iov[2].iov_base = &padding; ioc = (iov[2].iov_len > 0) ? 3 : 2; printf("pad: %d\n", ioc); param[0] = htonl(1); // BULK_FetchFile param[1] = htonl(1); param[2] = htonl(iov[1].iov_len); #endif msg.msg_name = (struct sockaddr *) &srx; msg.msg_namelen = sizeof(srx); msg.msg_iov = iov; msg.msg_iovlen = ioc; msg.msg_control = control; msg.msg_controllen = ctrllen; msg.msg_flags = 0; msg2.msg_name = NULL; msg2.msg_namelen = 0; msg2.msg_iov = iov2; msg2.msg_iovlen = ioc2; msg2.msg_control = control2; msg2.msg_controllen = ctrllen2; msg2.msg_flags = 0; ret = sendmsg(client, &msg, 0); if (ret == -1 && (errno == ENOANO || errno == ECONNABORTED)) perror("sendmsg/data"); else OSERROR(ret, "sendmsg/data"); // ret = sendmsg(client, &msg2, 0); // if (ret == -1 && (errno == ENOANO || errno == ECONNABORTED)) // perror("sendmsg/data"); // else // OSERROR(ret, "sendmsg/data"); // if (ret != -1) // sleep(1); /* abort the operation */ #if 0 ctrllen = 0; RXRPC_ADD_CALLID(control, ctrllen, 0x12345); RXRPC_ADD_ABORT(control, ctrllen, 0x6789); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = NULL; msg.msg_iovlen = 0; msg.msg_control = control; msg.msg_controllen = ctrllen; msg.msg_flags = 0; ret = sendmsg(client, &msg, 0); OSERROR(ret, "sendmsg/abort"); #endif /* wait for a reply */ for (;;) { iov[0].iov_base = buffer; iov[0].iov_len = sizeof(buffer); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_control = control; msg.msg_controllen = sizeof(control); msg.msg_flags = 0; ret = recvmsg(client, &msg, 0); OSERROR(ret, "recvmsg"); printf("RECV: %d [fl:%d]\n", ret, msg.msg_flags); printf("CMSG: %zu\n", msg.msg_controllen); printf("IOV: %zu [0]=%zu\n", msg.msg_iovlen, iov[0].iov_len); dump_cmsg(&msg); #if 1 for (loop = 0; loop < ret; loop++) { printf("%02x", buffer[loop]); if (loop % 40 == 39) putchar('\n'); else if (loop % 4 == 3) putchar(' '); } putchar('\n'); #endif } /* done */ ret = close(client); OSERROR(ret, "close"); return 0; }